IP Configuration

This commit is contained in:
Gašper Dobrovoljc
2023-03-11 15:11:03 +01:00
commit ec125f27db
662 changed files with 103738 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
#include "Constants.h"
namespace st
{
//private
//public
}

154
lib/ST_Anything/Constants.h Normal file
View File

@@ -0,0 +1,154 @@
//******************************************************************************************
// File: Constants.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: This file contains a number of user-definable settings that affect the
// ST_Anything library. This is the main file where user specific settings
// should be made to adjust the behavior of SmartThings Shield communications.
//
// Notes:
// -The SmartThings Shield uses Pins 0,1 or Pins 2,3 for serial communications based
// on the user selectable switch on the shield.
// -The SmartThings Shield reserves Pin 6 as well. Best to avoid using it.
// -The Arduino UNO R3 defaults to using the SoftwareSerial library since the UNO has
// only one Hardware UART port ("Serial") which is used by the USB port for
// programming and debugging typically.
// -You can use Hardware Serial with an UNO or Leonardo if desired, but you must suppress
// all "Serial.Print()" calls in your sketch, and make sure your Serial.begin() call
// is suppressed or set to use 2400 baud.
// -Arduino MEGA defaults to using the MEGA's "Serial3" Hardware UART serial port.
// This port uses pins 14(Tx) and 15(Rx). Wire Pin14 to Pin2 and Pin15 to Pin3.
// Be certain to not use Pins 2 & 3 in your Arduino sketch since they are still
// electrically connected to the ThingShield.
// -The SoftwareSerial library has the following known limitations:
// -If using multiple software serial ports, only one can receive data at a time.
// - Not all pins on the Mega and Mega 2560 support change interrupts, so only
// the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53,
// A8(62), A9(63), A10(64), A11(65), A12(66), A13(67), A14(68), A15(69).
// - Not all pins on the Leonardo and Micro support change interrupts, so only
// the following can be used for RX : 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-03-28 Dan Ogorchock Change the default DEV_REFRESH_INTERVAL to 300 seconds. Was interfering with normal operations.
// Added SENDSTRINGS_INTERVAL to throttle the rate at which data is sent to the ThingShield. Events were being missed.
// Added DISABLE_REFRESH feature - commented out by default. Allows user to disable the automatic refresh feature as it can interfere with normal operations.
// Adjusted MAX Sensor and Executor counts for the Arduino MEGA to allow 16 relay system to function properly.
// 2016-06-04 Dan Ogorchock Added improved support for Arduino Leonardo
// 2017-02-07 Dan Ogorchock Added support for new SmartThings v2.0 library (ThingShield, W5100, ESP8266)
// 2017-08-14 Dan Ogorchock Added support for ESP32
//
//******************************************************************************************
#ifndef ST_CONSTANTS_H
#define ST_CONSTANTS_H
//#include "Arduino.h"
#include "SmartThings.h"
//#define ENABLE_SERIAL //If uncommented, will allow you to type in commands via the Arduino Serial Console Window (useful for debugging)
//#define DISABLE_SMARTTHINGS //If uncommented, will disable all ST Shield Library calls (e.g. you want to use this library without SmartThings for a different application)
//#define DISABLE_REFRESH //If uncommented, will disable periodic refresh of the sensors and executors states to the ST Cloud - improves performance, but may reduce data integrity
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(ARDUINO_AVR_UNO)
#define BOARD_UNO
#elif defined(__AVR_ATmega32U4__) || defined(ARDUINO_AVR_LEONARDO)
#define BOARD_LEONARDO
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(ARDUINO_AVR_MEGA2560)
#define BOARD_MEGA
#elif defined(ARDUINO_ARCH_SAMD)
#define BOARD_MKR1000
#elif defined(ARDUINO_ARCH_ESP8266)
#define BOARD_ESP8266
#elif defined(ARDUINO_ARCH_ESP32)
#define BOARD_ESP32
#else
#define BOARD_UNO //assume user is using an UNO for the unknown case
#endif
namespace st
{
class Constants
{
public:
//Max name length (including null terminator!)
static const byte MAX_NAME_LENGTH=30;
//Serial debug console baud rate
static const unsigned long SERIAL_BAUDRATE=115200; //Uncomment If NOT using pins 0,1 for ST Shield communications (default)
//static const unsigned int SERIAL_BAUDRATE=2400; //Uncomment if using Pins 0,1 for ST Shield Communications
#if defined(BOARD_MEGA) || defined(BOARD_MKR1000) || defined(BOARD_ESP8266) || defined(BOARD_ESP32)
//Maximum number of SENSOR objects
static const byte MAX_SENSOR_COUNT=30; //Used to limit the number of sensor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation
//Maximum number of EXECUTOR objects
static const byte MAX_EXECUTOR_COUNT=20; //Used to limit the number of executor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation
#else
//Maximum number of SENSOR objects
static const byte MAX_SENSOR_COUNT = 10; //Used to limit the number of sensor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation
//Maximum number of EXECUTOR objects
static const byte MAX_EXECUTOR_COUNT = 10; //Used to limit the number of executor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation
#endif
//Size of reserved return string
static const byte RETURN_STRING_RESERVE = (MAX_SENSOR_COUNT + MAX_EXECUTOR_COUNT) * 5; //Do not make too large due to UNO's 2K SRAM limitation
//Interval on which Device's refresh methods are called (in seconds) - most useful for Executors and InterruptSensors - only works if DISABLE_REFRESH is not defined above
static const int DEV_REFRESH_INTERVAL=300; //seconds - Used to make sure the ST Cloud is kept current with device status (in case of missed updates to the ST Cloud) - primarily for Executors and InterruptSensors - only works if DISABLE_REFRESH is not defined above
//NOTE: The following constant was removed and replaced by a user defineable interval in the SmartThings library constaructors to permit different values for each communication method (i.e. ThingShield requires 1000ms, whereas Ethernet is ~100ms)
//Minumum interval between sending packets of data to ThingShield (in milliseconds) - noticed issue where ST Hub/Cloud could not keep up with rapid data transfer
//static const int SENDSTRINGS_INTERVAL = 100;
// -------------------------------------------------------------------------------
// --- SmartThings specific items
// -------------------------------------------------------------------------------
//--- if true, the sketch will stall until the ST ThingShield has joined the ST Hub (set to false for debugging without a ST ThingShield, but with SmartThings code still enabled)
static const bool WAIT_FOR_JOIN_AT_START = true;
//Select whether to use Hardware or Software Serial Communications - will result in the correct SmartThings constructor being called in Everything.cpp
//#if defined(BOARD_UNO)
// #define ST_SOFTWARE_SERIAL //Use Software Serial for UNO by default
// //#define ST_HARDWARE_SERIAL
//#elif defined(BOARD_MEGA) || defined(BOARD_LEONARDO)
// //#define ST_SOFTWARE_SERIAL
// #define ST_HARDWARE_SERIAL //Use Hardware Serial for MEGA or LEONARDO by default
//#else
// #define ST_SOFTWARE_SERIAL
// //#define ST_HARDWARE_SERIAL
//#endif
//---
//--- if using SoftwareSerial
//--- -set the following based on the pins you desire
//--- -NOTE: you must use the SoftwareSerial version of the SmartThings Constructor
//---
//#if defined(BOARD_UNO)
// static const uint8_t pinRX = 3; //Rx Pin3 - works for UNO R3, but not for Leonardo or Mega
//#else
// static const uint8_t pinRX = 10; //Rx Pin10 - works for Leonardo or Mega - You MUST jumper Pin10 to Pin3 - do not use Pin3 or Pin10 in your sketch!
//#endif
//
// static const uint8_t pinTX = 2; //Tx Pin2 - works for UNO R3, Leonardo, and Mega
//---
//--- if using Hardware Serial
//--- -set the following based on the pins you desire (HW_SERIAL, Mega Only(HW_SERIAL1, HW_SERIAL2, HW_SERIAL3))
//--- -NOTE: you must use the HardwareSerial version of the SmartThings Constructor
//---
//#if defined(BOARD_UNO)
// static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL; //UNO - You MUST move ThingShield switch to D0/D1 position after loading program and then reset the Arduino
//#elif defined(BOARD_LEONARDO)
// static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL1; //Leonardo - You MUST move ThingShield switch to D0/D1 position
//#elif defined(BOARD_MEGA)
// //static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL; //MEGA - You MUST move ThingShield switch to D0/D1 position after loading program and then reset the Arduino
// //static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL1; //MEGA - You MUST jumper Pin18 to Pin2 AND Pin19 to Pin3 - do not use Pin2 or Pin3 in your sketch!
// //static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL2; //MEGA - You MUST jumper Pin16 to Pin2 AND Pin17 to Pin3 - do not use Pin2 or Pin3 in your sketch!
// static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL3; //MEGA - You MUST jumper Pin14 to Pin2 AND Pin15 to Pin3 - do not use Pin2 or Pin3 in your sketch!
//#endif
// -------------------------------------------------------------------------------
};
}
#endif

View File

@@ -0,0 +1,68 @@
//******************************************************************************************
// File: Device.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Device is the highest level generic class for either a st::Sensor or
// st::Executor subclass.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2018-08-15 Dan Ogorchock Workaround for strcpy_P() ESP32 crash bug
//
//******************************************************************************************
#include "Device.h"
#include "Everything.h"
#include "Constants.h"
namespace st
{
//private
//public
//constructor
Device::Device(const __FlashStringHelper *name):
m_pName(name)
{
if(debug)
{
Serial.print(F("Device: New Device ID: "));
Serial.println(getName());
}
}
//destructor
Device::~Device()
{
if(debug)
{
Serial.print(F("Device: Destroyed Device ID: "));
Serial.println(getName());
}
}
void Device::refresh()
{
}
const String Device::getName() const
{
#if defined(ARDUINO_ARCH_ESP32)
return String((const char*)m_pName); //strcpy_P() causes ESP32 to crash
#else
char tmp[Constants::MAX_NAME_LENGTH];
strcpy_P(tmp, (const char*)m_pName);
return String(tmp);
#endif
}
//debug flag to determine if debug print statements are executed (set value in your sketch)
bool Device::debug=false;
}

57
lib/ST_Anything/Device.h Normal file
View File

@@ -0,0 +1,57 @@
//******************************************************************************************
// File: Device.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Device is the highest level generic class for either a st::Sensor or
// st::Executor subclass.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2019-02-09 Dan Ogorchock Moved update() from Sensor to Device
//
//
//******************************************************************************************
#ifndef ST_DEVICE_H
#define ST_DEVICE_H
#include <Arduino.h>
//#include <avr/pgmspace.h>
namespace st
{
class Device
{
private:
const __FlashStringHelper *m_pName;
public:
//constructor
Device(const __FlashStringHelper *name);
//destructor
virtual ~Device();
//initialization routine - This pure virtual function must be implemented by all derived classes
virtual void init()=0;
virtual void update() = 0;
//function used by all devices to process data from SmartThings Shield - all derived classes must implement this pure virtual function
virtual void beSmart(const String &str)=0;
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of each Device subclass object
virtual void refresh();
//gets
const String getName() const;
//debug flag to determine if debug print statements are executed (set value in your sketch)
static bool debug;
};
}
#endif

View File

@@ -0,0 +1,191 @@
//******************************************************************************************
// File: EX_Alarm.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: EX_Alarm is a class which implements the SmartThings "Alarm" device capability.
// It inherits from the st::PollingSensor class. The current version implements the Siren as
// a digital output (uses a relay to switch the Siren on or off)
//
// TODO: Possibly add Strobe capability in the future
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Alarm executor2(F("alarm1"), PIN_ALARM, LOW, true, PIN_STROBE);
//
// st::EX_Alarm() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
// - byte pinStrobe - OPTOINAL - If supplied, will allow separate SIREN and STROBE outputs
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2017-04-20 Dan Ogorchock Add optional Strobe functionality
// 2017-04-26 Dan Ogorchock Improved Logic if Strobe pin not defined
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#include "EX_Alarm.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void EX_Alarm::writeStateToPin()
{
if (m_nCurrentAlarmState == both) {
digitalWrite(m_nPin, m_bInvertLogic ? LOW : HIGH);
if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? LOW : HIGH); }
}
else if(m_nCurrentAlarmState == siren) {
digitalWrite(m_nPin, m_bInvertLogic ? LOW : HIGH);
if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? HIGH : LOW); }
}
else if(m_nCurrentAlarmState == strobe) {
digitalWrite(m_nPin, m_bInvertLogic ? HIGH : LOW);
if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? LOW : HIGH); }
}
else if(m_nCurrentAlarmState == off) {
digitalWrite(m_nPin, m_bInvertLogic ? HIGH : LOW);
if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? HIGH : LOW); }
}
}
//public
//constructor
EX_Alarm::EX_Alarm(const __FlashStringHelper *name, byte pin, bool startingState, bool invertLogic, byte pinStrobe) :
Executor(name),
m_nPin(pin),
m_bInvertLogic(invertLogic),
m_nPinStrobe(pinStrobe)
{
m_nCurrentAlarmState = off;
m_bUseStrobe = false;
setPin(pin);
//If user has supplied a pin for Strobe Light
if (pinStrobe < 255) {
m_bUseStrobe = true;
setPin(pinStrobe);
}
//else
//{
// m_bUseStrobe = false;
//}
}
//destructor
EX_Alarm::~EX_Alarm()
{
}
//initialization routine
void EX_Alarm::init()
{
refresh(); //update ST Cloud with initial data
}
//called periodically to ensure state of the Alarm Siren is up to date in the SmartThings Cloud (in case an event is missed)
void EX_Alarm::refresh()
{
//if (debug) {
// Serial.print(F("EX_Alarm:: UseStrobe = "));
// Serial.println(m_bUseStrobe);
//}
if (m_nCurrentAlarmState == both) {
Everything::sendSmartString(getName() + F(" both"));
}
else if(m_nCurrentAlarmState == siren) {
Everything::sendSmartString(getName() + F(" siren"));
}
else if(m_nCurrentAlarmState == strobe) {
Everything::sendSmartString(getName() + F(" strobe"));
}
else if(m_nCurrentAlarmState == off) {
//else {
Everything::sendSmartString(getName() + F(" off"));
}
}
//SmartThings Shield data handler (receives command to turn "both" or "off" the Alarm (digital output)
void EX_Alarm::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (debug) {
Serial.print(F("EX_Alarm::beSmart s = "));
Serial.println(s);
}
//if (m_bUseStrobe) {
if (s == F("both")) {
if (m_bUseStrobe) {
m_nCurrentAlarmState = both;
}
else {
m_nCurrentAlarmState = siren;
if (debug) {
Serial.println(F("EX_Alarm::beSmart - Strobe Pin not defined. Defaulting to Siren!"));
}
}
}
else if(s == F("siren")) {
m_nCurrentAlarmState = siren;
}
else if(s == F("strobe")) {
if (m_bUseStrobe) {
m_nCurrentAlarmState = strobe;
}
else {
m_nCurrentAlarmState = siren;
if (debug) {
Serial.println(F("EX_Alarm::beSmart - Strobe Pin not defined. Defaulting to Siren!"));
}
}
}
else if(s == F("off")) {
m_nCurrentAlarmState = off;
}
//}
//else {
// if (s == F("both") {
// m_nCurrentAlarmState = both;
// }
// else if(s == F("siren")) {
// m_nCurrentAlarmState = siren;
// }
// else if(s == F("strobe")) {
// m_nCurrentAlarmState = siren;
// }
// else if(s == F("off")) {
// m_nCurrentAlarmState = off;
// }
//}
writeStateToPin();
refresh();
}
void EX_Alarm::setPin(byte pin)
{
//m_nPin = pin;
digitalWrite(pin, m_bInvertLogic ? HIGH : LOW);
pinMode(pin, OUTPUT);
writeStateToPin();
}
}

View File

@@ -0,0 +1,82 @@
//******************************************************************************************
// File: EX_Alarm.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: EX_Alarm is a class which implements the SmartThings "Alarm" device capability.
// It inherits from the st::PollingSensor class. The current version implements the Siren as
// a digital output (uses a relay to switch the Siren on or off)
//
// TODO: Possibly add Strobe capability in the future
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Alarm executor2(F("alarm1"), PIN_ALARM, LOW, true, PIN_STROBE);
//
// st::EX_Alarm() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
// - byte pinStrobe - OPTOINAL - If supplied, will allow separate SIREN and STROBE outputs
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2017-04-20 Dan Ogorchock Add optional Strobe functionality
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#ifndef ST_EX_Alarm_H
#define ST_EX_Alarm_H
#include "Executor.h"
enum Alarm_States { off, both, siren, strobe};
namespace st
{
class EX_Alarm : public Executor
{
private:
bool m_bInvertLogic;
byte m_nPin;
byte m_nPinStrobe;
bool m_bUseStrobe;
Alarm_States m_nCurrentAlarmState;
void writeStateToPin();
public:
//constructor
EX_Alarm(const __FlashStringHelper *name, byte Pin, bool startingState = LOW, bool invertLogic = false, byte pinStrobe = 255);
//destructor
virtual ~EX_Alarm();
//initialization function
virtual void init();
//called periodically to ensure state of the Alarm Siren is up to date in the SmartThings Cloud (in case an event is missed)
virtual void refresh();
//SmartThings Shield data handler (receives command to turn "both" or "off" the Alarm (digital output)
virtual void beSmart(const String &str);
//gets
virtual byte getPin() const { return m_nPin; }
virtual byte getStrobePin() const { return m_nPinStrobe; }
//sets
virtual void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,201 @@
//******************************************************************************************
// File: EX_PWM_Dim.cpp
// Authors: Dan G Ogorchock
//
// Summary: EX_PWM_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_PWM_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true);
//
// st::EX_PWM_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2018-08-30 Dan Ogorchock Adding reporting of 'level'
// 2018-12-06 Dan Ogorchock Fixed Comments
// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform
// 2019-12-19 Doug Johnson Created new file based on EX_Switch_Dim to remove separate switch, and add dedicated smoothing
// 2020-04-01 Dan Ogorchock Added compatability for traditional Arduino Boards
//
//
//******************************************************************************************
#include "EX_PWM_Dim.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void EX_PWM_Dim::writeLevelToPin()
{
if((m_nCurrentLevel == 0) && (m_bSetState == HIGH))
{
for(int i=1; i < m_nSetLevel; i++)
{
m_nCurrentLevel++;
#if defined(ARDUINO_ARCH_ESP32)
if (st::Executor::debug) {
Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!"));
}
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023));
#else
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255));
#endif
delay(7);
}
}
if((m_nCurrentLevel > 0) && (m_bSetState == LOW))
{
for(int i=m_nCurrentLevel; i > 0; i--)
{
m_nCurrentLevel--;
#if defined(ARDUINO_ARCH_ESP32)
if (st::Executor::debug) {
Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!"));
}
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023));
#else
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255));
#endif
delay(7);
}
}
if((m_nCurrentLevel < m_nSetLevel)&& (m_bSetState == HIGH))
{
for(int i=m_nCurrentLevel; i < m_nSetLevel; i++)
{
m_nCurrentLevel++;
#if defined(ARDUINO_ARCH_ESP32)
if (st::Executor::debug) {
Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!"));
}
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023));
#else
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255));
#endif
delay(7);
}
}
if(m_nCurrentLevel > m_nSetLevel)
{
for(int i=m_nCurrentLevel; i > m_nSetLevel; i--)
{
m_nCurrentLevel--;
#if defined(ARDUINO_ARCH_ESP32)
if (st::Executor::debug) {
Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!"));
}
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023));
#else
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255));
#endif
delay(7);
}
}
if(m_nCurrentLevel == 0)
{
m_bCurrentState = LOW;
}
else
{
m_bCurrentState = HIGH;
}
}
//public
//constructor
EX_PWM_Dim::EX_PWM_Dim(const __FlashStringHelper *name, byte pinPWM, bool startingState, bool invertLogic) :
Executor(name),
m_bCurrentState(startingState),
m_bInvertLogic(invertLogic)
{
m_nCurrentLevel = startingState == HIGH ? 100 : 0;
setPWMPin(pinPWM);
}
//destructor
EX_PWM_Dim::~EX_PWM_Dim()
{
}
void EX_PWM_Dim::init()
{
//Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
refresh();
}
void EX_PWM_Dim::beSmart(const String &str)
{
//String s = str.substring(str.indexOf(' ') + 1, str.indexOf(':'));
//String dur = str.substring(str.indexOf(':') + 1);
//dur.trim();
String s = str.substring(str.indexOf(' ') + 1);
if (st::Executor::debug) {
Serial.print(F("EX_PWM_Dim::beSmart s = "));
Serial.println(s);
}
if (s == F("on"))
{
m_bSetState = HIGH;
}
else if (s == F("off"))
{
m_bSetState = LOW;
}
else //must be a set level command
{
s.trim();
m_nSetLevel = byte(s.toInt());
if (m_nSetLevel == 0)
{
m_bSetState = LOW;
}
else
{
m_bSetState = HIGH;
}
}
writeLevelToPin();
//Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
refresh();
}
void EX_PWM_Dim::refresh()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
Everything::sendSmartString(getName() + " " + m_nSetLevel);
}
void EX_PWM_Dim::setPWMPin(byte pin)
{
m_nPinPWM = pin;
pinMode(m_nPinPWM, OUTPUT);
writeLevelToPin();
}
}

View File

@@ -0,0 +1,82 @@
//******************************************************************************************
// File: EX_PWM_Dim.h
// Authors: Dan G Ogorchock
//
// Summary: EX_PWM_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_PWM_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true);
//
// st::EX_PWM_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2018-12-06 Dan Ogorchock Fixed Comments
// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform
// 2019-12-19 Doug Johnson Created new file based on EX_Switch_Dim to remove separate switch, and add dedicated smoothing
// 2020-04-01 Dan Ogorchock Added compatability for traditional Arduino Boards
//
//
//******************************************************************************************
#ifndef ST_EX_PWM_DIM
#define ST_EX_PWM_DIM
#include "Executor.h"
namespace st
{
class EX_PWM_Dim: public Executor
{
private:
bool m_bCurrentState; //HIGH or LOW
bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic
bool m_bSetState;
//byte m_nPinSwitch; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
byte m_nPinPWM; //Arduino Pin used as a PWM Output for the switch level capability
byte m_nCurrentLevel; //Switch Level value from SmartThings (0 to 100)
byte m_nSetLevel;
//void writeStateToPin(); //function to update the Arduino Digital Output Pin
void writeLevelToPin(); //function to update the Arduino PWM Output Pin
public:
//constructor - called in your sketch's global variable declaration section
EX_PWM_Dim(const __FlashStringHelper *name, byte pinPWM, bool startingState = LOW, bool invertLogic = false);
//destructor
virtual ~EX_PWM_Dim();
//initialization routine
virtual void init();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) and the LEVEL (PWM Output)
virtual void beSmart(const String &str);
//called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed)
virtual void refresh();
//gets
virtual byte getPWMPin() const { return m_nPinPWM; }
virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW
virtual bool getLevel() const { return m_nCurrentLevel; } //Dim Level of the switch
//sets
//virtual void setSwitchPin(byte pin);
virtual void setPWMPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,239 @@
//******************************************************************************************
// File: EX_RGBW_Dim.h
// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock
//
// Summary: EX_RGBW_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_RGBW_Dim executor1("rgbwSwitch1", PIN_R, PIN_G, PIN_B, PIN_W, true, 0, 1, 2, 3);
//
// st::EX_RGBW_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red.
// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green.
// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue.
// - byte pin_w - REQUIRED - the Arduino Pin to be used as a digital output for White.
// - bool commonAnode - REQUIRED - determines whether the LED uses a common Anode or Cathode. True for Anode.
// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32.
// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32.
// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32.
// - byte channel_w - OPTIONAL - PWM channel used for Whitw on a ESP32.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2017-10-08 Allan (vseven) Modified original code from EX_RGBW_Dim to be used for RGB lighting
// 2017-10-12 Allan (vseven) Modified EX_RGBW_Dim for support of a White LED channel
// 2018-04-02 Dan Ogorchock Fixed Typo
// 2020-06-09 Dan Ogorchock Scaled the 8bit values to 10bit for ESP8266 "analogWrite()"
//
//******************************************************************************************
#include "EX_RGBW_Dim.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void EX_RGBW_Dim::writeRGBWToPins()
{
int subStringR;
int subStringG;
int subStringB;
int subStringW;
if (m_bCurrentState == HIGH) {
// Our status is on so get the RGBW value from the hex
String hexstring = m_sCurrentHEX;
unsigned long number = (unsigned long) strtoul( &hexstring[1], NULL, 16);
// Split them up into r, g, b, w values
subStringR = number >> 24;
subStringG = number >> 16 & 0xFF;
subStringB = number >> 8 & 0xFF;
subStringW = number & 0xFF;
} else {
// Status is off so turn off LED
subStringR = 00;
subStringG = 00;
subStringB = 00;
subStringW = 00;
}
if(m_bCommonAnode) {
// A hex value of 00 will translate to 255 for a common anode. However the
// ledcWrite seems to need a 256 to turn off so we are adding one here.
#if defined(ARDUINO_ARCH_ESP32)
subStringR = 255 - subStringR + 1;
subStringG = 255 - subStringG + 1;
subStringB = 255 - subStringB + 1;
subStringW = 255 - subStringW + 1;
#else
subStringR = 255 - subStringR;
subStringG = 255 - subStringG;
subStringB = 255 - subStringB;
subStringW = 255 - subStringW;
#endif
}
// Write to outputs. Use ledc for ESP32, analogWrite for everything else.
if (st::Executor::debug) {
#if defined(ARDUINO_ARCH_ESP32)
Serial.print(F("subString R:G:B:W = "));
Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB) + ":" + String(subStringW));
#elif defined(ARDUINO_ARCH_ESP8266)
Serial.print(F("subString R:G:B:W = "));
Serial.println(String(map(subStringR, 0, 255, 0, 1023)) + ":" + String(map(subStringG, 0, 255, 0, 1023)) + ":" + String(map(subStringB, 0, 255, 0, 1023)) + ":" + String(map(subStringW, 0, 255, 0, 1023)));
#else
Serial.print(F("subString R:G:B:W = "));
Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB) + ":" + String(subStringW));
#endif
}
// Any adjustments to the colors can be done here before sending the commands. For example if red is always too bright reduce it:
// subStringR = subStringR * 0.95
#if defined(ARDUINO_ARCH_ESP32)
ledcWrite(m_nChannelR, subStringR);
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinR, map(subStringR, 0, 255, 0, 1023));
#else
analogWrite(m_nPinR, subStringR);
#endif
#if defined(ARDUINO_ARCH_ESP32)
ledcWrite(m_nChannelG, subStringG);
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinG, map(subStringG, 0, 255, 0, 1023));
#else
analogWrite(m_nPinG, subStringG);
#endif
#if defined(ARDUINO_ARCH_ESP32)
ledcWrite(m_nChannelB, subStringB);
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinB, map(subStringB, 0, 255, 0, 1023));
#else
analogWrite(m_nPinB, subStringB);
#endif
#if defined(ARDUINO_ARCH_ESP32)
ledcWrite(m_nChannelW, subStringW);
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinW, map(subStringW, 0, 255, 0, 1023));
#else
analogWrite(m_nPinW, subStringW);
#endif
}
//public
//constructor
EX_RGBW_Dim::EX_RGBW_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, byte pinW, bool commonAnode, byte channelR, byte channelG, byte channelB, byte channelW):
Executor(name),
m_bCommonAnode(commonAnode)
{
setRedPin(pinR, channelR);
setGreenPin(pinG, channelG);
setBluePin(pinB, channelB);
setWhitePin(pinW, channelW);
}
//destructor
EX_RGBW_Dim::~EX_RGBW_Dim()
{
}
void EX_RGBW_Dim::init()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
}
void EX_RGBW_Dim::beSmart(const String &str)
{
String s=str.substring(str.indexOf(' ')+1);
if (st::Executor::debug) {
Serial.print(F("EX_RGBW_Dim::beSmart s = "));
Serial.println(s);
}
if(s==F("on"))
{
m_bCurrentState=HIGH;
}
else if(s==F("off"))
{
m_bCurrentState=LOW;
}
else //must be a set color command
{
s.trim();
m_sCurrentHEX = s;
}
writeRGBWToPins();
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
}
void EX_RGBW_Dim::refresh()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
}
void EX_RGBW_Dim::setRedPin(byte pin, byte channel)
{
m_nPinR = pin;
m_nChannelR = channel;
#if defined(ARDUINO_ARCH_ESP32)
ledcAttachPin(m_nPinR, m_nChannelR);
ledcSetup(m_nChannelR, 5000, 8);
#else
pinMode(m_nPinR, OUTPUT);
#endif
}
void EX_RGBW_Dim::setGreenPin(byte pin, byte channel)
{
m_nPinG = pin;
m_nChannelG = channel;
#if defined(ARDUINO_ARCH_ESP32)
ledcAttachPin(m_nPinG, m_nChannelG);
ledcSetup(m_nChannelG, 5000, 8);
#else
pinMode(m_nPinG, OUTPUT);
#endif
}
void EX_RGBW_Dim::setBluePin(byte pin, byte channel)
{
m_nPinB = pin;
m_nChannelB = channel;
#if defined(ARDUINO_ARCH_ESP32)
ledcAttachPin(m_nPinB, m_nChannelB);
ledcSetup(m_nChannelB, 5000, 8);
#else
pinMode(m_nPinB, OUTPUT);
#endif
}
void EX_RGBW_Dim::setWhitePin(byte pin, byte channel)
{
m_nPinW = pin;
m_nChannelW = channel;
#if defined(ARDUINO_ARCH_ESP32)
ledcAttachPin(m_nPinW, m_nChannelW);
ledcSetup(m_nChannelW, 5000, 8);
#else
pinMode(m_nPinW, OUTPUT);
#endif
}
}

View File

@@ -0,0 +1,98 @@
//******************************************************************************************
// File: EX_RGBW_Dim.h
// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock
//
// Summary: EX_RGBW_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_RGBW_Dim executor1("rgbwSwitch1", PIN_R, PIN_G, PIN_B, PIN_W, true, 0, 1, 2, 3);
//
// st::EX_RGBW_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name.
// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red.
// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green.
// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue.
// - byte pin_w - REQUIRED - the Arduino Pin to be used as a digital output for White.
// - bool commonAnode - REQUIRED - determines whether the LED uses a common Anode or Cathode. True for Anode.
// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32.
// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32.
// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32.
// - byte channel_w - OPTIONAL - PWM channel used for Whitw on a ESP32.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2017-10-06 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting
// 2017-10-12 Allan (vseven) Modified EX_RGB_Dim for support of a White LEd channel
// 2020-06-09 Dan Ogorchock Scaled the 8bit values to 10bit for ESP8266 "analogWrite()"
//
//******************************************************************************************
#ifndef ST_EX_RGBW_Dim
#define ST_EX_RGBW_Dim
#include "Executor.h"
namespace st
{
class EX_RGBW_Dim: public Executor
{
private:
bool m_bCurrentState; //HIGH or LOW
bool m_bCommonAnode; //TRUE or FALSE
byte m_nPinR; //Arduino Pin used as a PWM Output for Red
byte m_nPinG; //Arduino Pin used as a PWM Output for Green
byte m_nPinB; //Arduino Pin used as a PWM Output for Blue
byte m_nPinW; //Arduino Pin used as a PWM Output for White
byte m_nChannelR; //PWM Channel used for Red output
byte m_nChannelG; //PWM Channel used for Green output
byte m_nChannelB; //PWM Channel used for Blue output
byte m_nChannelW; //PWM Channel used for White output
String m_sCurrentHEX; //HEX value of color currently set
void writeRGBWToPins(); //function to update the Arduino PWM Output Pins
public:
//constructor - called in your sketch's global variable declaration section
EX_RGBW_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, byte pinW, bool commonAnode, byte channelR = 0, byte channelG = 0, byte channelB = 0, byte channelW = 0);
//destructor
virtual ~EX_RGBW_Dim();
//initialization routine
virtual void init();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch along with HEX value for LEDs)
virtual void beSmart(const String &str);
//called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed)
virtual void refresh();
//gets
virtual byte getRedPin() const { return m_nPinR; }
virtual byte getGreenPin() const { return m_nPinG; }
virtual byte getBluePin() const { return m_nPinB; }
virtual byte getWhitePin() const { return m_nPinW; }
virtual byte getRedChannel() const { return m_nChannelR; }
virtual byte getGreenChannel() const { return m_nChannelG; }
virtual byte getBlueChannel() const { return m_nChannelB; }
virtual byte getWhiteChannel() const { return m_nChannelW; }
virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW
virtual String getHEX() const { return m_sCurrentHEX; } // color value in HEX
//sets
virtual void setRedPin(byte pin,byte channel);
virtual void setGreenPin(byte pin,byte channel);
virtual void setBluePin(byte pin,byte channel);
virtual void setWhitePin(byte pin,byte channel);
};
}
#endif

View File

@@ -0,0 +1,213 @@
//******************************************************************************************
// File: EX_RGB_Dim.h
// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock
//
// Summary: EX_RGB_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_RGB_Dim executor1("rgbSwitch1", PIN_R, PIN_G, PIN_B, true, 0, 1, 2);
//
// st::EX_RGB_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red
// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green
// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue
// - bool commonAnode - REQUIRED - determines whether the Arduino Digital Output should use inverted logic
// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32
// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32
// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2017-10-08 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2020-03-29 DOUG (M2) Scaled the 8bit values to 10bit for ESP8266 "analogWrite()"
// 2020-04-01 Dan Ogorchock Added back in functionality for traditional Arduino Boards
//
//******************************************************************************************
#include "EX_RGB_Dim.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void EX_RGB_Dim::writeRGBToPins()
{
int subStringR;
int subStringG;
int subStringB;
if (m_bCurrentState == HIGH)
{
// Our status is on so get the RGB value from the hex
String hexstring = m_sCurrentHEX;
long number = (long) strtol( &hexstring[1], NULL, 16);
// Split them up into r, g, b values
subStringR = number >> 16;
subStringG = number >> 8 & 0xFF;
subStringB = number & 0xFF;
}
else
{
// Status is off so turn off LED
subStringR = 00;
subStringG = 00;
subStringB = 00;
}
if(m_bCommonAnode)
{
// A hex value of 00 will translate to 255 for a common anode. However the
// ledcWrite seems to need a 256 to turn off so we are adding one here.
#if defined(ARDUINO_ARCH_ESP32)
subStringR = 255 - subStringR + 1;
subStringG = 255 - subStringG + 1;
subStringB = 255 - subStringB + 1;
#else
subStringR = 255 - subStringR;
subStringG = 255 - subStringG;
subStringB = 255 - subStringB;
#endif
}
// Write to outputs. Use ledc for ESP32, analogWrite for everything else.
if (st::Executor::debug) {
#if defined(ARDUINO_ARCH_ESP32)
Serial.print(F("subString R:G:B = "));
Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB));
#elif defined(ARDUINO_ARCH_ESP8266)
Serial.print(F("subString 10bit R:G:B = "));
Serial.println(String(map(subStringR, 0, 255, 0, 1023)) + ":" + String(map(subStringG, 0, 255, 0, 1023)) + ":" + String(map(subStringB, 0, 255, 0, 1023)));
#else
Serial.print(F("subString R:G:B = "));
Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB));
#endif
}
// Any adjustments to the colors can be done here before sending the commands. For example if red is always too bright reduce it:
// subStringR = subStringR * 0.95
#if defined(ARDUINO_ARCH_ESP32)
ledcWrite(m_nChannelR, subStringR);
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinR, map(subStringR, 0, 255, 0, 1023));
#else
analogWrite(m_nPinR, subStringR);
#endif
#if defined(ARDUINO_ARCH_ESP32)
ledcWrite(m_nChannelG, subStringG);
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinG, map(subStringG, 0, 255, 0, 1023));
#else
analogWrite(m_nPinG, subStringG);
#endif
#if defined(ARDUINO_ARCH_ESP32)
ledcWrite(m_nChannelB, subStringB);
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinB, map(subStringB, 0, 255, 0, 1023));
#else
analogWrite(m_nPinB, subStringB);
#endif
}
//public
//constructor
EX_RGB_Dim::EX_RGB_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, bool commonAnode, byte channelR, byte channelG, byte channelB):
Executor(name),
m_bCommonAnode(commonAnode)
{
setRedPin(pinR, channelR);
setGreenPin(pinG, channelG);
setBluePin(pinB, channelB);
}
//destructor
EX_RGB_Dim::~EX_RGB_Dim()
{
}
void EX_RGB_Dim::init()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
}
void EX_RGB_Dim::beSmart(const String &str)
{
String s=str.substring(str.indexOf(' ')+1);
if (st::Executor::debug) {
Serial.print(F("EX_RGB_Dim::beSmart s = "));
Serial.println(s);
}
if(s==F("on"))
{
m_bCurrentState=HIGH;
}
else if(s==F("off"))
{
m_bCurrentState=LOW;
}
else //must be a set color command
{
s.trim();
m_sCurrentHEX = s;
}
writeRGBToPins();
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
}
void EX_RGB_Dim::refresh()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
}
void EX_RGB_Dim::setRedPin(byte pin, byte channel)
{
m_nPinR = pin;
m_nChannelR = channel;
#if defined(ARDUINO_ARCH_ESP32)
ledcAttachPin(m_nPinR, m_nChannelR);
ledcSetup(m_nChannelR, 5000, 8);
#else
pinMode(m_nPinR, OUTPUT);
#endif
}
void EX_RGB_Dim::setGreenPin(byte pin, byte channel)
{
m_nPinG = pin;
m_nChannelG = channel;
#if defined(ARDUINO_ARCH_ESP32)
ledcAttachPin(m_nPinG, m_nChannelG);
ledcSetup(m_nChannelG, 5000, 8);
#else
pinMode(m_nPinG, OUTPUT);
#endif
}
void EX_RGB_Dim::setBluePin(byte pin, byte channel)
{
m_nPinB = pin;
m_nChannelB = channel;
#if defined(ARDUINO_ARCH_ESP32)
ledcAttachPin(m_nPinB, m_nChannelB);
ledcSetup(m_nChannelB, 5000, 8);
#else
pinMode(m_nPinB, OUTPUT);
#endif
}
}

View File

@@ -0,0 +1,91 @@
//******************************************************************************************
// File: EX_RGB_Dim.h
// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock
//
// Summary: EX_RGB_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_RGB_Dim executor1("rgbSwitch1", PIN_R, PIN_G, PIN_B, true, 0, 1, 2);
//
// st::EX_RGB_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name.
// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red.
// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green.
// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue.
// - bool commonAnode - REQUIRED - determines whether the LED uses a common Anode or Cathode. True for Anode.
// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32.
// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32.
// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2017-10-06 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2020-03-29 DOUG (M2) Scaled the 8bit values to 10bit for ESP8266 "analogWrite()"
// 2020-04-01 Dan Ogorchock Added back in functionality for traditional Arduino Boards
//
//******************************************************************************************
#ifndef ST_EX_RGB_DIM
#define ST_EX_RGB_DIM
#include "Executor.h"
namespace st
{
class EX_RGB_Dim: public Executor
{
private:
bool m_bCurrentState; //HIGH or LOW
bool m_bCommonAnode; //TRUE or FALSE
byte m_nPinR; //Arduino Pin used as a PWM Output for Red
byte m_nPinG; //Arduino Pin used as a PWM Output for Green
byte m_nPinB; //Arduino Pin used as a PWM Output for Blue
byte m_nChannelR; //PWM Channel used for Red output
byte m_nChannelG; //PWM Channel used for Green output
byte m_nChannelB; //PWM Channel used for Blue output
String m_sCurrentHEX; //HEX value of color currently set
void writeRGBToPins(); //function to update the Arduino PWM Output Pins
public:
//constructor - called in your sketch's global variable declaration section
EX_RGB_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, bool commonAnode, byte channelR = 0, byte channelG = 0, byte channelB = 0);
//destructor
virtual ~EX_RGB_Dim();
//initialization routine
virtual void init();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch along with HEX value for LEDs)
virtual void beSmart(const String &str);
//called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed)
virtual void refresh();
//gets
virtual byte getRedPin() const { return m_nPinR; }
virtual byte getGreenPin() const { return m_nPinG; }
virtual byte getBluePin() const { return m_nPinB; }
virtual byte getRedChannel() const { return m_nChannelR; }
virtual byte getGreenChannel() const { return m_nChannelG; }
virtual byte getBlueChannel() const { return m_nChannelB; }
virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW
virtual String getHEX() const { return m_sCurrentHEX; } // color value in HEX
//sets
virtual void setRedPin(byte pin,byte channel);
virtual void setGreenPin(byte pin,byte channel);
virtual void setBluePin(byte pin,byte channel);
};
}
#endif

View File

@@ -0,0 +1,198 @@
//******************************************************************************************
// File: EX_Servo.cpp
// Authors: Dan G Ogorchock
//
// Summary: EX_Servo is a class which implements the SmartThings/Hubitat "Switch Level" device capability.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Servo executor1(F("servo1"), PIN_SERVO, 90, true, 1000, 0, 180, 2000, 544, 2400);
//
// st::EX_Servo() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output
// - int startingAngle - OPTIONAL - the value desired for the initial angle of the servo motor (0 to 180, defaults to 90)
// - bool detachAfterMove - OPTIONAL - determines if servo motor is powered down after move (defaults to false)
// - int servoDetachTime - OPTIONAL - determines how long after the servo is moved that the servo is powered down if detachAfterMove is true (defaults to 1000ms)
// - int minLevelAngle - OPTIONAL - servo angle in degrees to map to level 0 (defaults to 0 degrees)
// - int maxLevelAngle - OPTIONAL - servo angle in degrees to map to level 100 (defaults to 180 degrees)
// - int servoRate - OPTIONAL - initial servo rate in ms/degree (defaults to 2000, used to ensure a gentle move during startup, afterwards comes from SmartThings/Hubitat with each move request)
// - int minPulseWidth - OPTIONAL - minimum pulse width in milliseconds, defaults to 544 (see Arduino servo attach() function)
// - int maxPulseWidth - OPTIONAL - maximum pulse width in milliseconds, defaults to 2400 (see Arduino servo attach() function)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2018-06-23 Dan Ogorchock Original Creation
// 2018-06-24 Dan Ogorchock Since ESP32 does not support SERVO library, exclude all code to prevent compiler error
// 2018-08-19 Dan Ogorchock Added feature to optionally allow servo to be powered down after a move
// 2019-02-02 Jeff Albers Added Parameters to map servo endpoints, actively control rate of servo motion via duration input to device driver, intializes to level instead of angle
// 2019-02-09 Dan Ogorchock Adding Asynchronous Motion to eliminate blocking calls and to allow simultaneous motion across multiple servos
// 2019-03-04 Dan Ogorchock Added optional min and max pulse width parameters to allow servo specific adjustments
//
//
//******************************************************************************************
#include "EX_Servo.h"
#include "Constants.h"
#include "Everything.h"
#if not defined(ARDUINO_ARCH_ESP32)
namespace st
{
//private
void EX_Servo::writeAngleToPin()
{
if(m_bMoveActive == true) {
m_bMoveActive = false;
}
if (!m_Servo.attached()) {
m_Servo.attach(m_nPinPWM, m_nMinPulseWidth, m_nMaxPulseWidth);
}
if ((m_nTargetAngle < m_nMinLevelAngle) and (m_nTargetAngle < m_nMaxLevelAngle)) {
if (m_nMinLevelAngle < m_nMaxLevelAngle) {
m_nTargetAngle = m_nMinLevelAngle;
}
else {
m_nTargetAngle = m_nMaxLevelAngle;
}
}
if ((m_nTargetAngle > m_nMaxLevelAngle) and (m_nTargetAngle > m_nMinLevelAngle)) {
if (m_nMaxLevelAngle > m_nMinLevelAngle) {
m_nTargetAngle = m_nMaxLevelAngle;
}
else {
m_nTargetAngle = m_nMinLevelAngle;
}
}
m_nTimeStep = abs(m_nCurrentRate / (m_nMaxLevelAngle - m_nMinLevelAngle)); //Constant servo step rate assumes duration is the time desired for maximum level change of 100
m_nCurrentAngle = m_nOldAngle; //preserver original angular position
m_bMoveActive = true; //start the move (the update() function will take care of the actual motion)
if (st::Executor::debug) {
Serial.print(F("EX_Servo:: Servo motor angle set to "));
Serial.println(m_nTargetAngle);
}
}
//public
//constructor
EX_Servo::EX_Servo(const __FlashStringHelper *name, byte pinPWM, int startingAngle, bool detachAfterMove, long servoDetachTime, int minLevelAngle, int maxLevelAngle, int servoRate, int minPulseWidth, int maxPulseWidth) :
Executor(name),
m_Servo(),
m_nTargetAngle(startingAngle),
m_bDetachAfterMove(detachAfterMove),
m_nDetachTime(servoDetachTime),
m_nMinLevelAngle(minLevelAngle),
m_nMaxLevelAngle(maxLevelAngle),
m_nCurrentRate(servoRate),
m_bMoveActive(false),
m_bDetachTmrActive(false),
m_nMinPulseWidth(minPulseWidth),
m_nMaxPulseWidth(maxPulseWidth)
{
setPWMPin(pinPWM);
m_nOldAngle = (minLevelAngle + maxLevelAngle) / 2;
}
//destructor
EX_Servo::~EX_Servo()
{
}
void EX_Servo::init()
{
writeAngleToPin();
refresh();
}
void EX_Servo::update()
{
if (m_bMoveActive) {
if ((millis() - m_nPrevMillis) > m_nTimeStep) {
m_nPrevMillis = millis();
if (m_nCurrentAngle != m_nTargetAngle) {
if (m_nTargetAngle >= m_nOldAngle) {
m_nCurrentAngle = m_nCurrentAngle + 1;
}
else {
m_nCurrentAngle = m_nCurrentAngle - 1;
}
m_Servo.write(m_nCurrentAngle);
}
else {
m_bMoveActive = false;
if (st::Executor::debug) {
Serial.println(F("EX_Servo::update() move complete"));
}
if (m_bDetachAfterMove) {
m_bDetachTmrActive = true;
}
refresh();
}
}
}
if (m_bDetachTmrActive) {
if ((millis() - m_nPrevMillis) > m_nDetachTime) {
m_bDetachTmrActive = false;
m_Servo.detach();
if (st::Executor::debug) {
Serial.println(F("EX_Servo::update() detach complete"));
}
}
}
}
void EX_Servo::beSmart(const String &str)
{
String level = str.substring(str.indexOf(' ') + 1, str.indexOf(':'));
String rate = str.substring(str.indexOf(':') + 1);
level.trim();
rate.trim();
if (st::Executor::debug) {
Serial.print(F("EX_Servo::beSmart level = "));
Serial.println(level);
Serial.print(F("EX_Servo::beSmart rate = "));
Serial.println(rate);
}
m_nCurrentLevel = int(level.toInt());
m_nCurrentRate = long(rate.toInt());
m_nOldAngle = m_nCurrentAngle;
m_nTargetAngle = map(m_nCurrentLevel, 0, 100, m_nMinLevelAngle, m_nMaxLevelAngle);
if (st::Executor::debug) {
Serial.print(F("EX_Servo::beSmart OldAngle = "));
Serial.println(m_nOldAngle);
Serial.print(F("EX_Servo::beSmart TargetAngle = "));
Serial.println(m_nTargetAngle);
Serial.print(F("EX_Servo::beSmart CurrentRate = "));
Serial.println(m_nCurrentRate);
}
writeAngleToPin();
}
void EX_Servo::refresh()
{
Everything::sendSmartString(getName() + " " + String(m_nCurrentLevel) + ":" + String(m_nTargetAngle) + ":" + String(m_nCurrentRate));
}
void EX_Servo::setPWMPin(byte pin)
{
m_nPinPWM = pin;
}
}
#endif

102
lib/ST_Anything/EX_Servo.h Normal file
View File

@@ -0,0 +1,102 @@
//******************************************************************************************
// File: EX_Servo.h
// Authors: Dan G Ogorchock
//
// Summary: EX_Servo is a class which implements the SmartThings/Hubitat "Switch Level" device capability.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Servo executor1(F("servo1"), PIN_SERVO, 90, true, 1000, 0, 180, 2000, 544, 2400);
//
// st::EX_Servo() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output
// - int startingAngle - OPTIONAL - the value desired for the initial angle of the servo motor (0 to 180, defaults to 90)
// - bool detachAfterMove - OPTIONAL - determines if servo motor is powered down after move (defaults to false)
// - int servoDetachTime - OPTIONAL - determines how long after the servo is moved that the servo is powered down if detachAfterMove is true (defaults to 1000ms)
// - int minLevelAngle - OPTIONAL - servo angle in degrees to map to level 0 (defaults to 0 degrees)
// - int maxLevelAngle - OPTIONAL - servo angle in degrees to map to level 100 (defaults to 180 degrees)
// - int servoRate - OPTIONAL - initial servo rate in ms/degree (defaults to 2000, used to ensure a gentle move during startup, afterwards comes from SmartThings/Hubitat with each move request)
// - int minPulseWidth - OPTIONAL - minimum pulse width in milliseconds, defaults to 544 (see Arduino servo attach() function)
// - int maxPulseWidth - OPTIONAL - maximum pulse width in milliseconds, defaults to 2400 (see Arduino servo attach() function)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2018-06-23 Dan Ogorchock Original Creation
// 2018-06-24 Dan Ogorchock Since ESP32 does not support SERVO library, exclude all code to prevent compiler error
// 2018-08-19 Dan Ogorchock Added feature to optionally allow servo to be powered down after a move
// 2019-02-02 Jeff Albers Added Parameters to map servo endpoints, actively control rate of servo motion via duration input to device driver, intializes to level instead of angle
// 2019-02-09 Dan Ogorchock Adding Asynchronous Motion to eliminate blocking calls and to allow simultaneous motion across multiple servos
// 2019-03-04 Dan Ogorchock Added optional min and max pulse width parameters to allow servo specific adjustments
//
//
//******************************************************************************************
#ifndef ST_EX_SERVO
#define ST_EX_SERVO
#if not defined(ARDUINO_ARCH_ESP32)
#include "Executor.h"
#include <Servo.h>
namespace st
{
class EX_Servo: public Executor
{
private:
Servo m_Servo; //Servo object
byte m_nPinPWM; //Arduino Pin used as a PWM Output for the switch level capability
int m_nCurrentLevel; //Servo Level value from SmartThings/Hubitat (0 to 100%)
int m_nOldAngle; //starting angle for servo move
int m_nTargetAngle; //ending angle for servo move, value mapped to Servo Level (0 to 180 degrees maximum range)
int m_nCurrentAngle; //servo angle output while stepping from OldAngle to TargetAngle
long m_nCurrentRate; //Servo move Duration value from SmartThings/Hubitat (0 to 10000 milliseconds)
long m_nDetachTime; //Servo Detach Time in milliseconds
bool m_bDetachAfterMove; //Issue a servo.detach() after servo move is complete
int m_nMinLevelAngle; //Angle (0-180 degrees)to map to level 0
int m_nMaxLevelAngle; //Angle (0-180 degrees)to map to level 100
bool m_bMoveActive; //True if servo move is active (asynchronous motion)
bool m_bDetachTmrActive; //True if servo is waiting to power off
long m_nTimeStep; //Number of milliseconds per servo motor degree (i.e. rate of change for the servo)
long m_nPrevMillis; //Previous millis() value
int m_nMinPulseWidth; //Minimum Servo Pulse Width
int m_nMaxPulseWidth; //Maximum Servo Pulse Width
void writeAngleToPin(); //function to update the Arduino PWM Output Pin
public:
//constructor - called in your sketch's global variable declaration section
EX_Servo(const __FlashStringHelper *name, byte pinPWM, int startingAngle = 90, bool detachAfterMove = false, long servoDetachTime = 1000, int minLevelAngle = 0, int maxLevelAngle = 180, int servoRate = 2000, int minPulseWidth = 544, int maxPulseWidth = 2400);
//destructor
virtual ~EX_Servo();
//initialization routine
virtual void init();
//update function
void update();
//SmartThings Shield data handler (receives Level and Duration from ST/Hubitat)
virtual void beSmart(const String &str);
//called periodically to ensure state of the switch is up to date in the SmartThings Cloud / Hubitat Hub (in case an event is missed)
virtual void refresh();
//gets
virtual byte getPWMPin() const { return m_nPinPWM; }
virtual bool getAngle() const { return m_nTargetAngle; } //Angle of the Servo mapped to Level
virtual bool getLevel() const { return m_nCurrentLevel; } //Servo Level from ST/Hubitat
virtual bool getRate() const { return m_nCurrentRate; } //Duration from ST/Hubitat
//sets
virtual void setPWMPin(byte pin);
};
}
#endif
#endif

View File

@@ -0,0 +1,95 @@
//******************************************************************************************
// File: EX_Switch.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: EX_Switch is a class which implements the SmartThings "Switch" device capability.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Switch executor1(F("switch1"), PIN_SWITCH, LOW, true);
//
// st::EX_Switch() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#include "EX_Switch.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void EX_Switch::writeStateToPin()
{
digitalWrite(m_nPin, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState);
}
//public
//constructor
EX_Switch::EX_Switch(const __FlashStringHelper *name, byte pin, bool startingState, bool invertLogic) :
Executor(name),
m_bCurrentState(startingState),
m_bInvertLogic(invertLogic)
{
setPin(pin);
}
//destructor
EX_Switch::~EX_Switch()
{
}
void EX_Switch::init()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
}
void EX_Switch::beSmart(const String &str)
{
String s=str.substring(str.indexOf(' ')+1);
if (st::Executor::debug) {
Serial.print(F("EX_Switch::beSmart s = "));
Serial.println(s);
}
if(s==F("on"))
{
m_bCurrentState=HIGH;
}
else if(s==F("off"))
{
m_bCurrentState=LOW;
}
writeStateToPin();
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
}
void EX_Switch::refresh()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
}
void EX_Switch::setPin(byte pin)
{
m_nPin=pin;
pinMode(m_nPin, OUTPUT);
writeStateToPin();
}
}

View File

@@ -0,0 +1,69 @@
//******************************************************************************************
// File: EX_Switch.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: EX_Switch is a class which implements the SmartThings "Switch" device capability.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Switch executor1(F("switch1"), PIN_SWITCH, LOW, true);
//
// st::EX_Switch() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#ifndef ST_EX_SWITCH
#define ST_EX_SWITCH
#include "Executor.h"
namespace st
{
class EX_Switch: public Executor
{
private:
bool m_bCurrentState; //HIGH or LOW
bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic
byte m_nPin; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
void writeStateToPin(); //function to update the Arduino Digital Output Pin
public:
//constructor - called in your sketch's global variable declaration section
EX_Switch(const __FlashStringHelper *name, byte pin, bool startingState = LOW, bool invertLogic = false);
//destructor
virtual ~EX_Switch();
//initialization routine
virtual void init();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output)
virtual void beSmart(const String &str);
//called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed)
virtual void refresh();
//gets
virtual byte getPin() const {return m_nPin;}
virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW
//sets
virtual void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,137 @@
//******************************************************************************************
// File: EX_Switch_Dim.cpp
// Authors: Dan G Ogorchock
//
// Summary: EX_Switch_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Switch_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true);
//
// st::EX_Switch_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2018-08-30 Dan Ogorchock Adding reporting of 'level'
// 2018-12-06 Dan Ogorchock Fixed Comments
// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform
//
//
//******************************************************************************************
#include "EX_Switch_Dim.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void EX_Switch_Dim::writeStateToPin()
{
digitalWrite(m_nPinSwitch, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState);
}
void EX_Switch_Dim::writeLevelToPin()
{
#if defined(ARDUINO_ARCH_ESP32)
if (st::Executor::debug) {
Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!"));
}
#elif defined(ARDUINO_ARCH_ESP8266)
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023));
#else
analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255));
#endif
}
//public
//constructor
EX_Switch_Dim::EX_Switch_Dim(const __FlashStringHelper *name, byte pinSwitch, byte pinPWM, bool startingState, bool invertLogic) :
Executor(name),
m_bCurrentState(startingState),
m_bInvertLogic(invertLogic)
{
m_nCurrentLevel = startingState == HIGH ? 100 : 0;
setSwitchPin(pinSwitch);
setPWMPin(pinPWM);
}
//destructor
EX_Switch_Dim::~EX_Switch_Dim()
{
}
void EX_Switch_Dim::init()
{
//Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
refresh();
}
void EX_Switch_Dim::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (st::Executor::debug) {
Serial.print(F("EX_Switch_Dim::beSmart s = "));
Serial.println(s);
}
if (s == F("on"))
{
m_bCurrentState = HIGH;
}
else if (s == F("off"))
{
m_bCurrentState = LOW;
}
else //must be a set level command
{
s.trim();
m_nCurrentLevel = byte(s.toInt());
if (m_nCurrentLevel == 0)
{
m_bCurrentState = LOW;
}
else
{
m_bCurrentState = HIGH;
}
}
writeStateToPin();
writeLevelToPin();
//Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
refresh();
}
void EX_Switch_Dim::refresh()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
Everything::sendSmartString(getName() + " " + m_nCurrentLevel);
}
void EX_Switch_Dim::setSwitchPin(byte pin)
{
m_nPinSwitch = pin;
pinMode(m_nPinSwitch, OUTPUT);
writeStateToPin();
}
void EX_Switch_Dim::setPWMPin(byte pin)
{
m_nPinPWM = pin;
pinMode(m_nPinPWM, OUTPUT);
writeLevelToPin();
}
}

View File

@@ -0,0 +1,79 @@
//******************************************************************************************
// File: EX_Switch_Dim.h
// Authors: Dan G Ogorchock
//
// Summary: EX_Switch_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities.
// It inherits from the st::Executor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_Switch_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true);
//
// st::EX_Switch_Dim() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output
// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2016-04-30 Dan Ogorchock Original Creation
// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2018-12-06 Dan Ogorchock Fixed Comments
// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform
//
//
//******************************************************************************************
#ifndef ST_EX_SWITCH_DIM
#define ST_EX_SWITCH_DIM
#include "Executor.h"
namespace st
{
class EX_Switch_Dim: public Executor
{
private:
bool m_bCurrentState; //HIGH or LOW
bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic
byte m_nPinSwitch; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
byte m_nPinPWM; //Arduino Pin used as a PWM Output for the switch level capability
byte m_nCurrentLevel; //Switch Level value from SmartThings (0 to 100)
void writeStateToPin(); //function to update the Arduino Digital Output Pin
void writeLevelToPin(); //function to update the Arduino PWM Output Pin
public:
//constructor - called in your sketch's global variable declaration section
EX_Switch_Dim(const __FlashStringHelper *name, byte pinSwitch, byte pinPWM, bool startingState = LOW, bool invertLogic = false);
//destructor
virtual ~EX_Switch_Dim();
//initialization routine
virtual void init();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) and the LEVEL (PWM Output)
virtual void beSmart(const String &str);
//called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed)
virtual void refresh();
//gets
virtual byte getSwitchPin() const {return m_nPinSwitch;}
virtual byte getPWMPin() const { return m_nPinPWM; }
virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW
virtual bool getLevel() const { return m_nCurrentLevel; } //Dim Level of the switch
//sets
virtual void setSwitchPin(byte pin);
virtual void setPWMPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,177 @@
//******************************************************************************************
// File: EX_TimedRelayPair.cpp
// Authors: Dan G Ogorchock
//
// Summary: EX_TimedRelayPair is a class which implements the "Valve" device capability, where output1 opens a valve, and
// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs.
//
// It inherits from the st::Executor class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_TimedRelayPair executor1(F("valve1"), PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000);
//
// st::EX_TimedRelayPair() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays)
// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-10-30 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#include "EX_TimedRelayPair.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void EX_TimedRelayPair::writeStateToPin(byte pin, bool state)
{
digitalWrite(pin, m_bInvertLogic ? !state : state);
}
//public
//constructor
EX_TimedRelayPair::EX_TimedRelayPair(const __FlashStringHelper *name, byte pinOutput1, byte pinOutput2, bool startingState, bool invertLogic, unsigned long Output1Time, unsigned long Output2Time) :
Executor(name),
m_nOutputPin1(pinOutput1),
m_nOutputPin2(pinOutput2),
m_bCurrentState(startingState),
m_bInvertLogic(invertLogic),
m_lOutput1Time(Output1Time),
m_lOutput2Time(Output2Time),
m_lTimeChanged(0),
m_bTimerPending(false)
{
//set pin mode
pinMode(m_nOutputPin1, OUTPUT);
pinMode(m_nOutputPin2, OUTPUT);
//update the digital outputs
if (((m_bCurrentState == HIGH) && (m_lOutput1Time > 0)) || ((m_bCurrentState == LOW) && (m_lOutput2Time > 0)))
{
m_bTimerPending = true;
}
m_lTimeChanged = millis();
writeStateToPin(m_nOutputPin1, m_bCurrentState);
writeStateToPin(m_nOutputPin2, !m_bCurrentState);
}
//destructor
EX_TimedRelayPair::~EX_TimedRelayPair()
{
}
void EX_TimedRelayPair::init()
{
refresh();
}
//update function
void EX_TimedRelayPair::update()
{
if (m_bTimerPending)
{
if ((m_bCurrentState == HIGH) && (millis() - m_lTimeChanged >= m_lOutput1Time))
{
writeStateToPin(m_nOutputPin1, LOW);
}
else if ((m_bCurrentState == LOW) && (millis() - m_lTimeChanged >= m_lOutput2Time))
{
writeStateToPin(m_nOutputPin2, LOW);
}
}
}
void EX_TimedRelayPair::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (st::Device::debug) {
Serial.print(F("EX_TimedRelayPair::beSmart s = "));
Serial.println(s);
}
//if ((s == F("open")) && (m_bCurrentState == LOW))
if (s == F("open"))
{
if (m_bTimerPending)
{
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
}
m_bCurrentState = HIGH;
//Save time turned on
m_lTimeChanged = millis();
//Increment number of active timers
if ((!m_bTimerPending) && (m_lOutput1Time > 0))
{
st::Everything::bTimersPending++;
m_bTimerPending = true;
}
//Queue the relay status update the ST Cloud
refresh();
//update the digital outputs
writeStateToPin(m_nOutputPin2, !m_bCurrentState);
writeStateToPin(m_nOutputPin1, m_bCurrentState);
}
//else if ((s == F("close")) && (m_bCurrentState == HIGH))
else if (s == F("close"))
{
if (m_bTimerPending)
{
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
}
m_bCurrentState = LOW;
//Save time turned on
m_lTimeChanged = millis();
//Increment number of active timers
if ((!m_bTimerPending) && (m_lOutput2Time > 0))
{
st::Everything::bTimersPending++;
m_bTimerPending = true;
}
//Queue the relay status update the ST Cloud
refresh();
//update the digital outputs
writeStateToPin(m_nOutputPin1, m_bCurrentState);
writeStateToPin(m_nOutputPin2, !m_bCurrentState);
}
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
void EX_TimedRelayPair::refresh()
{
//Queue the relay status update the ST Cloud
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("open") : F("closed")));
}
//void EX_TimedRelayPair::setOutputPin(byte pin)
//{
// pinMode(pin, OUTPUT);
//}
}

View File

@@ -0,0 +1,84 @@
//******************************************************************************************
// File: EX_TimedRelayPair.h
// Authors: Dan G Ogorchock
//
// Summary: EX_TimedRelayPair is a class which implements the "Valve" device capability, where output1 opens a valve, and
// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs.
//
// It inherits from the st::Executor class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::EX_TimedRelayPair executor1(F("valve1"), PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000);
//
// st::EX_TimedRelayPair() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays)
// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-10-30 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#ifndef ST_EX_TimedRelayPair_H
#define ST_EX_TimedRelayPair_H
#include "Executor.h"
namespace st
{
class EX_TimedRelayPair : public Executor //inherits from parent Executor Class
{
private:
//following are for the digital output
bool m_bCurrentState; //HIGH or LOW
bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic
byte m_nOutputPin1; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
byte m_nOutputPin2; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
unsigned long m_lOutput1Time; //number of milliseconds to keep digital output HIGH before automatically turning off
unsigned long m_lOutput2Time; //number of milliseconds to keep digital output HIGH before automatically turning off
unsigned long m_lTimeChanged; //time when the digital output was last changed
bool m_bTimerPending; //true if waiting on relay timer to expire
void writeStateToPin(byte, bool); //function to update the Arduino Digital Output Pin
public:
//constructor - called in your sketch's global variable declaration section
EX_TimedRelayPair(const __FlashStringHelper *name, byte pinOutput1, byte pinOutput2, bool startingState = LOW, bool invertLogic = false, unsigned long Output1Time = 1000, unsigned long Output2Time = 1000);
//destructor
virtual ~EX_TimedRelayPair();
//initialization function
virtual void init();
//update function
void update();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output)
virtual void beSmart(const String &str);
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
virtual void refresh();
//gets
//virtual byte getPin() const { return m_nOutputPin; }
virtual bool getTimerActive() const { return m_bTimerPending; }
virtual bool getStatus() const { return m_bCurrentState; }
//sets
//virtual void setOutputPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,428 @@
//******************************************************************************************
// File: Everything.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Everything is a generic class which essentially acts as the main() routine.
// All st::Device type objects are managed by st::Everything. It is responsible for
// for calling the correct functions within each object it is responsible for at the
// proper time. It handles all initialization of and use of the SmarThings Shield library.
//
// THere are user-definable settings which will impact the st::Everything class stored in
// Constants.h. Please edit Constants.h to adjust these settings.
//
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-01-10 Dan Ogorchock Minor improvements to support Door Control Capability
// 2015-03-14 Dan Ogorchock Added public setLED() function to control ThingShield LED
// 2015-03-28 Dan Ogorchock Added throttling capability to sendStrings to improve success rate of ST Cloud getting the data ("SENDSTRINGS_INTERVAL" is in CONSTANTS.H)
// 2017-02-07 Dan Ogorchock Added support for new SmartThings v2.0 library (ThingShield, W5100, ESP8266)
// 2017-02-19 Dan Ogorchock Fixed bug in throttling capability
// 2017-04-26 Dan Ogorchock Allow each communication method to specify unique ST transmission throttling delay
// 2019-02-09 Dan Ogorchock Add update() call to Executors in support of devices like EX_Servo that need a non-blocking mechanism
// 2019-02-24 Dan Ogorchock Added new special callOnMsgRcvd2 callback capability. Allows recvd string to be manipulated in the sketch before being processed by Everything.
// 2021-01-31 Marcus van Ierssel Improved the automatic refresh to prevent it from blocking other updates.
// 2021-05-23 Dan Ogorchock Address EXP8266 v3.0.0 board support package compatibility issue with Strings
//
//******************************************************************************************
//#include <Arduino.h>
//#include <avr/pgmspace.h>
#include "Everything.h"
long freeRam(); //freeRam() function prototype - useful in determining how much SRAM is available on Arduino
#if defined(ARDUINO_ARCH_SAMD)
extern "C" char* sbrk(int incr);
#endif
namespace st
{
//private
void Everything::updateDevices()
{
for(unsigned int index=0; index<m_nSensorCount; ++index)
{
m_Sensors[index]->update();
sendStrings();
}
for (unsigned int i = 0; i<m_nExecutorCount; ++i)
{
m_Executors[i]->update();
sendStrings();
}
}
#if defined(ENABLE_SERIAL)
void Everything::readSerial()
{
String message;
while(Serial.available()>0)
{
char c=Serial.read();
message+=c;
delay(10);
}
if(message.length()>0)
{
receiveSmartString(message);
}
}
#endif
void Everything::sendStrings()
{
unsigned int index;
//Loop through the Return_String buffer and send each "|" delimited string to ST Shield
while(Return_String.length()>=1 && Return_String[0]!='|')
{
index=Return_String.indexOf("|");
if(debug)
{
Serial.print(F("Everything: Sending: "));
Serial.println(Return_String.substring(0, index));
//Serial.print(F("Everything: getTransmitInterval() = "));
//Serial.println(SmartThing->getTransmitInterval());
}
#ifndef DISABLE_SMARTTHINGS
// if (millis() - sendstringsLastMillis < Constants::SENDSTRINGS_INTERVAL)
if (millis() - sendstringsLastMillis < SmartThing->getTransmitInterval())
{
// delay(Constants::SENDSTRINGS_INTERVAL - (millis() - sendstringsLastMillis)); //Added due to slow ST Hub/Cloud Processing. Events were being missed. DGO 2015-03-28
delay(SmartThing->getTransmitInterval() - (millis() - sendstringsLastMillis)); //modified to allow different values for each method of communicating to ST cloud. DGO 2017-04-26
}
SmartThing->send(Return_String.substring(0, index));
sendstringsLastMillis = millis();
#endif
#if defined(ENABLE_SERIAL) && defined(DISABLE_SMARTTHINGS)
Serial.println(Return_String.substring(0, index));
#endif
if(callOnMsgSend!=0)
{
callOnMsgSend(Return_String.substring(0, index));
}
Return_String=Return_String.substring(index+1);
}
Return_String.remove(0); //clear the Return_String buffer
}
void Everything::refreshDevices()
{
static int refresh_Executor = 0;
static int refresh_Sensor = 0;
/*
for(unsigned int i=0; i<m_nExecutorCount; ++i)
{
m_Executors[i]->refresh();
sendStrings();
}
for (unsigned int i = 0; i<m_nSensorCount; ++i)
{
m_Sensors[i]->refresh();
sendStrings();
}
*/
if (refresh_Executor < m_nExecutorCount) {
m_Executors[refresh_Executor]->refresh();
sendStrings();
refresh_Executor++;
refLastMillis = millis() - long(Constants::DEV_REFRESH_INTERVAL) * 1000 + 4 * SmartThing->getTransmitInterval();
}
else if (refresh_Sensor < m_nSensorCount) {
m_Sensors[refresh_Sensor]->refresh();
sendStrings();
refresh_Sensor++;
refLastMillis = millis() - long(Constants::DEV_REFRESH_INTERVAL) * 1000 + 4 * SmartThing->getTransmitInterval();
}
else {
refLastMillis = millis();
refresh_Executor = 0;
refresh_Sensor = 0;
}
}
//public
void Everything::init()
{
Serial.begin(Constants::SERIAL_BAUDRATE);
Return_String.reserve(st::Constants::RETURN_STRING_RESERVE); //allocate Return_String buffer one time to prevent Heap Fragmentation. RETURN_STRING_RESERVE is set in Constants.h
if(debug)
{
Serial.println(F("Everything: init started"));
Serial.print(F("Everything: Free RAM = "));
Serial.println(freeRam());
}
#ifndef DISABLE_SMARTTHINGS
SmartThing->init();
#endif
if(debug)
{
Serial.println(F("Everything: init ended"));
Serial.print(F("Everything: Free RAM = "));
Serial.println(freeRam());
}
}
void Everything::initDevices()
{
if(debug)
{
Serial.println(F("Everything: initDevices started"));
Serial.print(F("Everything: Free RAM = "));
Serial.println(freeRam());
}
for(unsigned int index=0; index<m_nSensorCount; ++index)
{
m_Sensors[index]->init();
sendStrings();
}
for(unsigned int index=0; index<m_nExecutorCount; ++index)
{
m_Executors[index]->init();
sendStrings();
}
if(debug)
{
Serial.println(F("Everything: initDevices ended"));
Serial.print(F("Everything: Free RAM = "));
Serial.println(freeRam());
}
refLastMillis = millis(); //avoid immediately refreshing after initialization
}
void Everything::run()
{
updateDevices(); //call each st::Sensor object to refresh data
#ifndef DISABLE_SMARTTHINGS
SmartThing->run(); //call the ST Shield Library to receive any data from the ST Hub
#endif
#if defined(ENABLE_SERIAL)
readSerial(); //read data from the Arduino IDE Serial Monitor window (useful for debugging sometimes)
#endif
sendStrings(); //send any pending updates to ST Cloud
#ifndef DISABLE_REFRESH //Added new check to allow user to disable REFRESH feature - setting is in Constants.h)
if ((bTimersPending == 0) && ((millis() - refLastMillis) >= long(Constants::DEV_REFRESH_INTERVAL) * 1000)) //DEV_REFRESH_INTERVAL is set in Constants.h
{
//refLastMillis = millis();
refreshDevices(); //call each st::Device object to refresh data (this is just a safeguard to ensure the state of the Arduino and the ST Cloud stay in synch should an event be missed)
}
#endif
if((debug) && (millis()%60000==0) && (millis()!=lastmillis))
{
lastmillis = millis();
Serial.print(F("Everything: Free Ram = "));
Serial.println(freeRam());
}
}
bool Everything::sendSmartString(const String &str)
{
//while(str.length()>1 && str[0]=='|') //get rid of leading pipes (messes up sendStrings()'s parsing technique)
//{
// str=str.substring(1);
//}
if((str.length()==1 && str[0]=='|') || str.length()==0)
{
return false;
}
if(Return_String.length()+str.length()>=Constants::RETURN_STRING_RESERVE)
{
if (debug)
{
Serial.print(F("Everything: ERROR: \""));
Serial.print(str);
Serial.println(F("\" would overflow the Return_String 'buffer'"));
}
return false;
}
else
{
Return_String+=str+"|"; //add the new message to the queue to be sent to ST Shield with a "|" delimiter
return true;
}
}
bool Everything::sendSmartStringNow(const String &str)
{
bool queued = sendSmartString(str);
if (queued) sendStrings(); //send any pending updates to ST Cloud immediately
return queued;
}
Device* Everything::getDeviceByName(const String &str)
{
for(unsigned int index=0; index<m_nSensorCount; ++index)
{
if(m_Sensors[index]->getName()==str)
return (Device*)m_Sensors[index];
}
for(unsigned int index=0; index<m_nExecutorCount; ++index)
{
if(m_Executors[index]->getName()==str)
return (Device*)m_Executors[index];
}
return 0; //null if no such device present
}
bool Everything::addSensor(Sensor *sensor)
{
if(m_nSensorCount>=Constants::MAX_SENSOR_COUNT)
{
if(debug)
{
Serial.print(F("Did not add sensor named "));
Serial.print(sensor->getName());
Serial.println(F("(You've exceeded maximum number of sensors; edit Constants.h)"));
}
return false;
}
else
{
m_Sensors[m_nSensorCount]=sensor;
++m_nSensorCount;
}
if(debug)
{
Serial.print(F("Everything: adding sensor named "));
Serial.println(sensor->getName());
Serial.print(F("Everything: Free RAM = "));
Serial.println(freeRam());
}
return true;
}
bool Everything::addExecutor(Executor *executor)
{
if(m_nExecutorCount>=Constants::MAX_EXECUTOR_COUNT)
{
if(debug)
{
Serial.print(F("Did not add executor named "));
Serial.print(executor->getName());
Serial.println(F("(You've exceeded maximum number of executors; edit Constants.h)"));
}
return false;
}
else
{
m_Executors[m_nExecutorCount]=executor;
++m_nExecutorCount;
}
if(debug)
{
Serial.print(F("Everything: adding executor named "));
Serial.println(executor->getName());
Serial.print(F("Everything: Free RAM = "));
Serial.println(freeRam());
}
return true;
}
//friends!
void receiveSmartString(String message)
{
message.trim();
if(Everything::debug && message.length()>1)
{
Serial.print(F("Everything: Received: "));
Serial.println(message);
}
if (Everything::callOnMsgRcvd2 != 0)
{
Everything::callOnMsgRcvd2(message);
}
if (message == "refresh")
{
Everything::refreshDevices();
}
else if (message.length() > 1) //ignore empty string messages from the ST Hub
{
Device *p = Everything::getDeviceByName(message.substring(0, message.indexOf(' ')));
if (p != 0)
{
p->beSmart(message); //pass the incoming SmartThings Shield message to the correct Device's beSmart() routine
}
}
if(Everything::callOnMsgRcvd!=0)
{
Everything::callOnMsgRcvd(message);
}
}
//initialize static members
st::SmartThings* Everything::SmartThing=0; //initialize pointer to null
String Everything::Return_String;
Sensor* Everything::m_Sensors[Constants::MAX_SENSOR_COUNT];
Executor* Everything::m_Executors[Constants::MAX_EXECUTOR_COUNT];
byte Everything::m_nSensorCount=0;
byte Everything::m_nExecutorCount=0;
unsigned long Everything::lastmillis=0;
unsigned long Everything::refLastMillis=0;
unsigned long Everything::sendstringsLastMillis=0;
bool Everything::debug=false;
byte Everything::bTimersPending=0; //initialize variable
void (*Everything::callOnMsgSend)(const String &msg)=0; //initialize this callback function to null
void (*Everything::callOnMsgRcvd)(const String &msg)=0; //initialize this callback function to null
void(*Everything::callOnMsgRcvd2)(String &msg) = 0; //initialize this callback function to null
//SmartThings static members
//#ifndef DISABLE_SMARTTHINGS
// // Please refer to Constants.h for settings that affect whether a board uses SoftwareSerial or Hardware Serial calls
// #if defined(ST_SOFTWARE_SERIAL) //use Software Serial
// SmartThingsThingShield Everything::SmartThing(Constants::pinRX, Constants::pinTX, receiveSmartString);
// #elif defined(ST_HARDWARE_SERIAL) //use Hardware Serial
// SmartThingsThingShield Everything::SmartThing(Constants::SERIAL_TYPE, receiveSmartString);
// #endif
// SmartThingsNetworkState_t Everything::stNetworkState=(SmartThingsNetworkState_t)99; //bogus value for first pass through Everything::updateNetworkState()
//#endif
}
//freeRam() function - useful in determining how much SRAM is available on Arduino
long freeRam()
{
#if defined(ARDUINO_ARCH_AVR)
extern int __heap_start, *__brkval;
int v;
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
return ESP.getFreeHeap();
#elif defined(ARDUINO_ARCH_SAMD)
char top;
return &top - reinterpret_cast<char*>(sbrk(0));
#else
return -1;
#endif // !
}

View File

@@ -0,0 +1,109 @@
//******************************************************************************************
// File: Everything.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Everything is a static class which essentially acts as the main() routine for
// a ST_Anything application.
// -All st::Device type objects (Sensors and Executors) are managed by st::Everything.
// -It calls the correct functions within each object it
// is responsible for at the proper time.
// -It handles all initialization of and use of the SmarThings Shield library.
//
// User-definable settings which will impact the st::Everything class are stored in
// Constants.h. Please edit Constants.h to adjust these settings.
//
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-01-10 Dan Ogorchock Minor improvements to support Door Control Capability
// 2015-03-14 Dan Ogorchock Added public setLED() function to control ThingShield LED
// 2015-03-28 Dan Ogorchock Added throttling capability to sendStrings to improve success rate of ST Cloud getting the data ("SENDSTRINGS_INTERVAL" is in CONSTANTS.H)
// 2017-02-07 Dan Ogorchock Added support for new SmartThings v2.0 library (ThingShield, W5100, ESP8266)
// 2019-02-09 Dan Ogorchock Add update() call to Executors in support of devices like EX_Servo that need a non-blocking mechanism
// 2019-02-24 Dan Ogorchock Added new special callOnMsgRcvd2 callback capability. Allows recvd string to be manipulated in the sketch before being processed by Everything.
// 2021-05-23 Dan Ogorchock Address EXP8266 v3.0.0 board support package compatibility issue with Strings
//
//******************************************************************************************
#ifndef ST_EVERYTHING_H
#define ST_EVERYTHING_H
//#include "Arduino.h"
#include "Constants.h"
#include "Sensor.h"
#include "Executor.h"
#include "SmartThings.h"
namespace st
{
SmartThingsCallout_t receiveSmartString; //function prototype for ST Library callback function
class Everything
{
private:
static Sensor* m_Sensors[Constants::MAX_SENSOR_COUNT]; //array of Sensor objects that st::Everything will keep track of
static byte m_nSensorCount; //number of st::Sensor objects added to st::Everything in your sketch Setup() routine
static Executor* m_Executors[Constants::MAX_EXECUTOR_COUNT]; //array of Executor objects that st::Everything will keep track of
static byte m_nExecutorCount;//number of st::Executor objects added to st::Everything in your sketch Setup() routine
//static SmartThingsNetworkState_t stNetworkState;
//static void updateNetworkState(); //keeps track of the current ST Shield to Hub network status
static void updateDevices(); //simply calls update on all the sensors
static void sendStrings(); //sends all updates from the devices in Return_String
static unsigned long sendstringsLastMillis; //keep track of how long since last time we sent data to ST Cloud, to enable throttling
static unsigned long lastmillis; //used to keep track of last time run() has output freeRam() info
//stuff for refreshing Devices
static unsigned long refLastMillis; //used to keep track of last time run() has called refreshDevices()
static void refreshDevices(); //simply calls refresh on all the Devices
#ifdef ENABLE_SERIAL
static void readSerial(); //reads data from Arduino IDE Serial Monitor, if enabled in Constants.h
#endif
static String Return_String; //static buffer for string data queued for transfer to SmartThings Shield - prevents dynamic memory allocation heap fragmentation
public:
static void init(); //st::Everything initialization routine called in your sketch setup() routine
static void initDevices(); //calls the init() routine of every object added to st::Everything in your sketch setup() routine
static void run(); //st::Everything initialization routine called in your sketch loop() routine
static bool sendSmartString(const String &str); //sendSmartString() may edit the string reference passed to it - queues messages - preferable
static bool sendSmartStringNow(const String &str); //sendSmartStringNow() may edit the string reference passed to it - sends messages immediate - only for special circumstances
static Device* getDeviceByName(const String &str); //returns pointer to Device object by name
static bool addSensor(Sensor *sensor); //adds a Sensor object to st::Everything's m_Sensors[] array - called in your sketch setup() routine
static bool addExecutor(Executor *executor);//adds a Executor object to st::Everything's m_Executors[] array - called in your sketch setup() routine
static byte bTimersPending; //number of time critical events in progress - if > 0, do NOT perform refreshDevices() routine
static bool debug; //debug flag to determine if debug print statements are executed - set value in your sketch's setup() routine
static void (*callOnMsgSend)(const String &msg); //If this function pointer is assigned, the function it points to will be called upon every time a string is sent to the cloud.
static void (*callOnMsgRcvd)(const String &msg); //If this function pointer is assigned, the function it points to will be called upon every time a string is received from the cloud.
static void(*callOnMsgRcvd2)(String &msg); //If this function pointer is assigned, the function it points to will be called upon every time a string is received from the cloud.
//SmartThings Object
#ifndef DISABLE_SMARTTHINGS
static st::SmartThings* SmartThing; //SmartThings Shield Library object
#endif
friend SmartThingsCallout_t receiveSmartString; //callback function to act on data received from SmartThings Shield - called from SmartThings Shield Library
//SmartThings Object
//#ifndef DISABLE_SMARTTHINGS
// static void setLED(uint8_t red, uint8_t green, uint8_t blue) {SmartThing.shieldSetLED(red, green, blue);}
//#endif
};
}
#endif

View File

@@ -0,0 +1,59 @@
//******************************************************************************************
// File: Executor.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Executor is a generic class which inherits from st::Device. This is the
// parent class for the st::EX_Switch class.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2019-02-09 Dan Ogorchock Added update() function
//
//
//******************************************************************************************
#include "Executor.h"
#include "Constants.h"
#include "Everything.h"
namespace
st
{
//private
//public
//constructor
Executor::Executor(const __FlashStringHelper *name):
Device(name)
{
}
//destructor
Executor::~Executor()
{
}
void Executor::init()
{
}
void Executor::update()
{
}
//debug flag to determine if debug print statements are executed (set value in your sketch)
bool Executor::debug=false;
}

View File

@@ -0,0 +1,54 @@
//******************************************************************************************
// File: Executor.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Executor is a generic class which inherits from st::Device. This is the
// parent class for the st::EX_Switch class.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2019-02-09 Dan Ogorchock Added update() function
//
//
//******************************************************************************************
#ifndef ST_EXECUTOR_H
#define ST_EXECUTOR_H
#include "Device.h"
namespace st
{
class Executor: public Device
{
private:
//Inherits private members from parent st::Device class
public:
//constructor
Executor(const __FlashStringHelper *name);
//destructor
virtual ~Executor();
//initialization routine
virtual void init();
//update function
virtual void update();
//debug flag to determine if debug print statements are executed (set value in your sketch)
static bool debug;
};
}
#endif

View File

@@ -0,0 +1,117 @@
//******************************************************************************************
// File: IS_Button.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Button is a class which implements the SmartThings "Contact Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Button sensor(F("button1"), PIN_BUTTON1, 1000, LOW, true, 500);
//
// st::IS_Button() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - should be "button1", "button2", "button3", etc...
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - long reqNumMillisHeld - Required - number of milliseconds required needed to detect a "Held" condition versus a "Pushed" (default = 1000)
// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true (default = HIGH)
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP (default - true)
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false triggers) (default = 500)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2017-03-25 Dan Original Creation
// 2019-09-7 Dan Ogorchock Send Button 'init' messages for automatic setting of numberOfButtons attribute
// 2020-09-19 Dan Ogorchock Modified to not wait until button is released to send 'held' event, also added released events
//
//******************************************************************************************
#include "IS_Button.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor
IS_Button::IS_Button(const __FlashStringHelper *name, byte pin, long reqNumMillisHeld, bool iState, bool internalPullup, long numReqCounts) :
InterruptSensor(name, pin, iState, internalPullup, numReqCounts), //use parent class' constructor
m_lreqNumMillisHeld(reqNumMillisHeld)
{
}
//destructor
IS_Button::~IS_Button()
{
}
void IS_Button::init()
{
//get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
//m_lTimeBtnPressed = 0;
refresh();
}
//called periodically by Everything class to ensure ST Cloud is kept up yo date. HOWEVER, not useful for the IS_Button.
void IS_Button::refresh()
{
//Send 'init' message to allow Parent Driver to set numberOfButtons attribute automatically
Everything::sendSmartString(getName() + F(" init"));
}
void IS_Button::update()
{
InterruptSensor::update();
if (getStatus())
{
if (((millis() - m_lTimeBtnPressed) >= m_lreqNumMillisHeld) && (!m_bHeldSent))
{
m_bHeldSent = true;
//add the "held" event to the buffer to be queued for transfer to SmartThings
Everything::sendSmartString(getName() + F(" held"));
}
}
}
void IS_Button::runInterrupt()
{
//Capture time of button down event so we can figure it whether to send "pushed" or "held" on button release
m_lTimeBtnPressed = millis();
//Serial.println("IS_Button: in runInterrupt()");
}
void IS_Button::runInterruptEnded()
{
//Serial.println("IS_Button: in runInterruptEnded()");
//Serial.println(millis());
//Serial.println(m_lTimeBtnPressed);
//Serial.println(m_lreqNumMillisHeld);
if (!m_bFirstRun) //Prevent sending data to SmartThings during initial startup
{
if ((millis() - m_lTimeBtnPressed) < m_lreqNumMillisHeld)
{
//immediately send the "pushed" event to the Hub (to make sure it arrives before the 'released' event)
Everything::sendSmartStringNow(getName() + F(" pushed"));
}
//add the "released" event to the buffer to be queued for transfer to Hub
Everything::sendSmartString(getName() + F(" released"));
m_bHeldSent = false;
}
else
{
m_bFirstRun = false;
}
}
}

View File

@@ -0,0 +1,68 @@
//******************************************************************************************
// File: IS_Button.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Button is a class which implements the SmartThings "Contact Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Button sensor(F("button1"), PIN_BUTTON1, 1000, LOW, true, 500);
//
// st::IS_Button() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - should be "button1", "button2", "button3", etc...
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - long reqNumMillisHeld - Required - number of milliseconds required needed to detect a "Held" condition versus a "Pushed" (default = 1000)
// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true (default = HIGH)
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP (default - true)
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false triggers) (default = 500)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2017-03-25 Dan Ogorchock Original Creation
// 2020-09-19 Dan Ogorchock Modified to not wait until button is released to send 'held' event, also added released events
//
//******************************************************************************************
#ifndef ST_IS_BUTTON_H
#define ST_IS_BUTTON_H
#include "InterruptSensor.h"
namespace st
{
class IS_Button: public InterruptSensor
{
private:
unsigned long m_lTimeBtnPressed; //time when the digital input went high
unsigned long m_lreqNumMillisHeld; //amount of time required to trigger "held" instead of "pushed"
bool m_bFirstRun = true; //used to prevent sending inadvertent button pushed/held message on startup
bool m_bHeldSent = false; //used to prevent sending multiple 'held' messages
public:
//constructor - called in your sketch's global variable declaration section
IS_Button(const __FlashStringHelper *name, byte pin, long reqNumMillisHeld = 1000, bool iState = LOW, bool internalPullup = true, long numReqCounts = 500); //(defaults to using internal pullup resistors)
//destructor
virtual ~IS_Button();
//initialization function
virtual void init();
//called periodically by Everything class to ensure ST Cloud is kept up to date. Not used for IS_Button.
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
//override update method
virtual void update();
};
}
#endif

View File

@@ -0,0 +1,73 @@
//******************************************************************************************
// File: IS_CarbonMonoxide.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Smoke is a class which implements the SmartThings "Carbon Monoxide Detector" device capability.
// It inherits from the st::IS_Smoke class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_CarbonMonoxide sensor6("carbonMonoxide1", PIN_CO, HIGH, false, 500);
//
// st::IS_CarbonMonoxide() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-04-19 Dan & Daniel Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#include "IS_CarbonMonoxide.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor
IS_CarbonMonoxide::IS_CarbonMonoxide(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts) :
InterruptSensor(name, pin, iState, pullup, numReqCounts) //use parent class' constructor
{
}
//destructor
IS_CarbonMonoxide::~IS_CarbonMonoxide()
{
}
void IS_CarbonMonoxide::init()
{
//get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
void IS_CarbonMonoxide::refresh()
{
Everything::sendSmartString(getName() + (getStatus() ? F(" clear") : F(" detected")));
}
void IS_CarbonMonoxide::runInterrupt()
{
//add the "closed" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" clear"));
}
void IS_CarbonMonoxide::runInterruptEnded()
{
//add the "open" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" detected"));
}
}

View File

@@ -0,0 +1,63 @@
//******************************************************************************************
// File: IS_CarbonMonoxide.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Smoke is a class which implements the SmartThings "Carbon Monoxide Detector" device capability.
// It inherits from the st::IS_Smoke class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_CarbonMonoxide sensor6("carbonMonoxide1", PIN_CO, HIGH, false, 500);
//
// st::IS_CarbonMonoxide() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-04-19 Dan & Daniel Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#ifndef ST_IS_CARBONMONOXIDE_H
#define ST_IS_CARBONMONOXIDE_H
#include "InterruptSensor.h"
namespace st
{
class IS_CarbonMonoxide: public InterruptSensor
{
private:
//inherits everything necessary from parent IS_Smoke Class
public:
//constructor - called in your sketch's global variable declaration section
IS_CarbonMonoxide(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0)
//destructor
virtual ~IS_CarbonMonoxide();
//initialization function
virtual void init();
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
};
}
#endif

View File

@@ -0,0 +1,74 @@
//******************************************************************************************
// File: IS_Contact.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Contact is a class which implements the SmartThings "Contact Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Contact sensor6(F("contact1"), PIN_CONTACT, HIGH, true, 500);
//
// st::IS_Contact() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#include "IS_Contact.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor
IS_Contact::IS_Contact(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup, long numReqCounts) :
InterruptSensor(name, pin, iState, internalPullup, numReqCounts) //use parent class' constructor
{
}
//destructor
IS_Contact::~IS_Contact()
{
}
void IS_Contact::init()
{
//get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
void IS_Contact::refresh()
{
Everything::sendSmartString(getName() + (getStatus() ? F(" closed") : F(" open")));
}
void IS_Contact::runInterrupt()
{
//add the "closed" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" closed"));
}
void IS_Contact::runInterruptEnded()
{
//add the "open" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" open"));
}
}

View File

@@ -0,0 +1,64 @@
//******************************************************************************************
// File: IS_Contact.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Contact is a class which implements the SmartThings "Contact Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Contact sensor6(F("contact1"), PIN_CONTACT, HIGH, true, 500);
//
// st::IS_Contact() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#ifndef ST_IS_CONTACT_H
#define ST_IS_CONTACT_H
#include "InterruptSensor.h"
namespace st
{
class IS_Contact: public InterruptSensor
{
private:
//inherits everything necessary from parent InterruptSensor Class
public:
//constructor - called in your sketch's global variable declaration section
IS_Contact(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0)
//destructor
virtual ~IS_Contact();
//initialization function
virtual void init();
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
};
}
#endif

View File

@@ -0,0 +1,162 @@
//******************************************************************************************
// File: IS_DoorControl.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_DoorControl is a class which implements the SmartThings "Door Control" device capability. It features
// an automatic-turn-off time delay for a relay to actuate a button press. This is useful for controlling
// a garage door. Use the input to monitor a magnetic door contact sensor. Use the output to control a relay to
// "press the garage door button" to open/close the garage door.
//
// It inherits from the st::InterruptSensor class and clones much from the st::Executor Class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_DoorControl sensor3(F("doorControl1"), PIN_CONTACT_DOOR_1, LOW, true, PIN_RELAY_DOOR_1, LOW, true, 1000, 1000, true);
//
// st::IS_DoorControl() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP
// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic
// - long delayTime - REQUIRED - the number of milliseconds to keep the output on
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
// - bool useMomentary - OPTIONAL - use momentary output (true) or standard switch (false) (defaults to true)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-07 Dan Ogorchock Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2018-11-07 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2019-07-24 Dan Ogorchock Added parameter to use output as a simple switch instead of momentary output
//
//
//******************************************************************************************
#include "IS_DoorControl.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void IS_DoorControl::writeStateToPin()
{
digitalWrite(m_nOutputPin, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState);
}
//public
//constructor
IS_DoorControl::IS_DoorControl(const __FlashStringHelper *name, byte pinInput, bool iState, bool pullup, byte pinOutput, bool startingState, bool invertLogic, unsigned long delayTime, long numReqCounts, bool useMomentary) :
InterruptSensor(name, pinInput, iState, pullup, numReqCounts), //use parent class' constructor
m_bCurrentState(startingState),
m_bInvertLogic(invertLogic),
m_lDelayTime(delayTime),
m_bUseMomentary(useMomentary),
m_lTimeTurnedOn(0),
m_bTimerPending(false)
{
setOutputPin(pinOutput);
}
//destructor
IS_DoorControl::~IS_DoorControl()
{
}
void IS_DoorControl::init()
{
//get current status of contact sensor by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
}
//update function
void IS_DoorControl::update()
{
if (m_bTimerPending) {
//Turn off digital output if timer has expired
if ((m_bCurrentState == HIGH) && (millis() - m_lTimeTurnedOn >= m_lDelayTime))
{
m_bCurrentState = LOW;
writeStateToPin();
//Decrement number of active timers
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
}
}
//check to see if input pin has changed state
InterruptSensor::update();
}
void IS_DoorControl::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (st::InterruptSensor::debug) {
Serial.print(F("IS_ContactRelay::beSmart s = "));
Serial.println(s);
}
if ( (s == F("on")) || (m_bUseMomentary && (s == F("off"))))
{
m_bCurrentState = HIGH;
if (m_bUseMomentary) {
//Save time turned on
m_lTimeTurnedOn = millis();
//Increment number of active timers
if (!m_bTimerPending)
{
st::Everything::bTimersPending++;
m_bTimerPending = true;
}
}
if (m_bUseMomentary) {
//Queue the door status update the ST Cloud
Everything::sendSmartStringNow(getName() + (getStatus() ? F(" opening") : F(" closing")));
}
}
else if (s == F("off"))
{
m_bCurrentState = LOW;
//Decrement number of active timers
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
}
//update the digital output
writeStateToPin();
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
void IS_DoorControl::refresh()
{
Everything::sendSmartString(getName() + (getStatus() ? F(" closed") : F(" open")));
}
void IS_DoorControl::runInterrupt()
{
//add the "closed" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" closed"));
}
void IS_DoorControl::runInterruptEnded()
{
//add the "open" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" open"));
}
void IS_DoorControl::setOutputPin(byte pin)
{
m_nOutputPin = pin;
pinMode(m_nOutputPin, OUTPUT);
writeStateToPin();
}
}

View File

@@ -0,0 +1,97 @@
//******************************************************************************************
// File: IS_DoorControl.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_DoorControl is a class which implements the SmartThings "Door Control" device capability. It features
// an automatic-turn-off time delay for a relay to actuate a button press. This is useful for controlling
// a garage door. Use the input to monitor a magnetic door contact sensor. Use the output to control a relay to
// "press the garage door button" to open/close the garage door.
//
// It inherits from the st::InterruptSensor class and clones much from the st::Executor Class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_DoorControl sensor3(F("doorControl1"), PIN_CONTACT_DOOR_1, LOW, true, PIN_RELAY_DOOR_1, LOW, true, 1000, 1000, true);
//
// st::IS_DoorControl() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP
// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic
// - long delayTime - REQUIRED - the number of milliseconds to keep the output on
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
// - bool useMomentary - OPTIONAL - use momentary output (true) or standard switch (false) (defaults to true)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-07 Dan Ogorchock Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2018-11-07 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2019-07-24 Dan Ogorchock Added parameter to use output as a simple switch instead of momentary output
//
//
//******************************************************************************************
#ifndef ST_IS_DOORCONTROL_H
#define ST_IS_DOORCONTROL_H
#include "InterruptSensor.h"
namespace st
{
class IS_DoorControl : public InterruptSensor
{
private:
//inherits everything necessary from parent InterruptSensor Class for the Contact Sensor
//following are for the digital output
bool m_bCurrentState; //HIGH or LOW
bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic
bool m_bUseMomentary; //determines whether the output should be momentary or simple switch
byte m_nOutputPin; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
unsigned long m_lDelayTime; //number of milliseconds to keep digital output active before automatically turning off
unsigned long m_lTimeTurnedOn; //time when the digital output was turned on
bool m_bTimerPending; //true if waiting on relay timer to expire
void writeStateToPin(); //function to update the Arduino Digital Output Pin
public:
//constructor - momentary output - called in your sketch's global variable declaration section
IS_DoorControl(const __FlashStringHelper *name, byte pinInput, bool iState, bool pullup, byte pinOutput, bool startingState, bool invertLogic, unsigned long delayTime, long numReqCounts = 0, bool useMomentary = true);
//destructor
virtual ~IS_DoorControl();
//initialization function
virtual void init();
//update function
void update();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output)
virtual void beSmart(const String &str);
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
//gets
virtual byte getPin() const { return m_nOutputPin; }
//sets
virtual void setOutputPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,206 @@
//******************************************************************************************
// File: IS_LatchingRelaySwitch.cpp
// Authors: Dan G Ogorchock
//
// Summary: IS_LatchingRelaySwitch is a class which implements the "Valve" device capability, where output1 opens a valve, and
// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs.
//
// It inherits from the st::InterruptSensor class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_LatchingRelaySwitch sensor1(F("switch1"), PIN_INPUT, HIGH, true, 500, PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000);
//
// st::IS_LatchingRelaySwitch() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input to determine the switch state of latching relay
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP
// - long numReqCounts - REQUIRED - number of counts before changing state of input (prevent false alarms)
// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays)
// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
// - bool initializeOutputs - OPTIONAL - determines if the digital outputs are activated during initialization/startup, defaults to 'false'
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2020-06-26 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#include "IS_LatchingRelaySwitch.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void IS_LatchingRelaySwitch::writeStateToPin(byte pin, bool state)
{
digitalWrite(pin, m_bInvertLogic ? !state : state);
}
//public
//constructor
IS_LatchingRelaySwitch::IS_LatchingRelaySwitch(const __FlashStringHelper *name, byte pinInput, bool iState, bool internalPullup, long numReqCounts, byte pinOutput1, byte pinOutput2, bool startingState, bool invertLogic, unsigned long Output1Time, unsigned long Output2Time, bool initializeOutputs) :
InterruptSensor(name, pinInput, iState, internalPullup, numReqCounts), //use parent class' constructor,
m_nOutputPin1(pinOutput1),
m_nOutputPin2(pinOutput2),
m_bCurrentState(startingState),
m_bInvertLogic(invertLogic),
m_lOutput1Time(Output1Time),
m_lOutput2Time(Output2Time),
m_lTimeChanged(0),
m_bTimerPending(false)
{
//set pin mode
pinMode(m_nOutputPin1, OUTPUT);
pinMode(m_nOutputPin2, OUTPUT);
if (initializeOutputs)
{
//update the digital outputs
if (((m_bCurrentState == HIGH) && (m_lOutput1Time > 0)) || ((m_bCurrentState == LOW) && (m_lOutput2Time > 0)))
{
m_bTimerPending = true;
}
m_lTimeChanged = millis();
writeStateToPin(m_nOutputPin1, m_bCurrentState);
writeStateToPin(m_nOutputPin2, !m_bCurrentState);
}
else
{
//Make sure both digital outputs are 'off' if initializeOutputs == false
writeStateToPin(m_nOutputPin1, LOW);
writeStateToPin(m_nOutputPin2, LOW);
}
}
//destructor
IS_LatchingRelaySwitch::~IS_LatchingRelaySwitch()
{
}
void IS_LatchingRelaySwitch::init()
{
//get current status of switch by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
//refresh();
}
//update function
void IS_LatchingRelaySwitch::update()
{
if (m_bTimerPending)
{
if ((m_bCurrentState == HIGH) && (millis() - m_lTimeChanged >= m_lOutput1Time))
{
writeStateToPin(m_nOutputPin1, LOW);
}
else if ((m_bCurrentState == LOW) && (millis() - m_lTimeChanged >= m_lOutput2Time))
{
writeStateToPin(m_nOutputPin2, LOW);
}
}
//make sure to call the parent class' update() since we overrode it for the above timer logic
InterruptSensor::update();
}
void IS_LatchingRelaySwitch::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (st::Device::debug) {
Serial.print(F("IS_LatchingRelaySwitch::beSmart s = "));
Serial.println(s);
}
//if ((s == F("open")) && (m_bCurrentState == LOW))
if (s == F("on"))
{
if (m_bTimerPending)
{
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
}
m_bCurrentState = HIGH;
//Save time turned on
m_lTimeChanged = millis();
//Increment number of active timers
if ((!m_bTimerPending) && (m_lOutput1Time > 0))
{
st::Everything::bTimersPending++;
m_bTimerPending = true;
}
//Queue the relay status update the ST Cloud
//refresh();
//update the digital outputs
writeStateToPin(m_nOutputPin2, !m_bCurrentState);
writeStateToPin(m_nOutputPin1, m_bCurrentState);
}
//else if ((s == F("close")) && (m_bCurrentState == HIGH))
else if (s == F("off"))
{
if (m_bTimerPending)
{
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
}
m_bCurrentState = LOW;
//Save time turned on
m_lTimeChanged = millis();
//Increment number of active timers
if ((!m_bTimerPending) && (m_lOutput2Time > 0))
{
st::Everything::bTimersPending++;
m_bTimerPending = true;
}
//Queue the relay status update the Hub
//refresh();
//update the digital outputs
writeStateToPin(m_nOutputPin1, m_bCurrentState);
writeStateToPin(m_nOutputPin2, !m_bCurrentState);
}
}
//called periodically by Everything class to ensure Hub is kept consistent with the state of the contact sensor
void IS_LatchingRelaySwitch::refresh()
{
//Queue the relay status update the Hub
//Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
Everything::sendSmartString(getName() + (getStatus() ? F(" off") : F(" on")));
}
void IS_LatchingRelaySwitch::runInterrupt()
{
//add the "closed" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" off"));
}
void IS_LatchingRelaySwitch::runInterruptEnded()
{
//add the "open" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" on"));
}
}

View File

@@ -0,0 +1,93 @@
//******************************************************************************************
// File: IS_LatchingRelaySwitch.h
// Authors: Dan G Ogorchock
//
// Summary: IS_LatchingRelaySwitch is a class which implements the "Valve" device capability, where output1 opens a valve, and
// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs.
//
// It inherits from the st::InterruptSensor class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_LatchingRelaySwitch sensor1(F("switch1"), PIN_INPUT, HIGH, true, 500, PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000);
//
// st::IS_LatchingRelaySwitch() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input to determine switch the state of latching relay
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP
// - long numReqCounts - REQUIRED - number of counts before changing state of input (prevent false alarms)
// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output
// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays)
// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on
// - bool initializeOutputs - OPTIONAL - determines if the digital outputs are activated during initialization/startup, defaults to 'false'
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2020-06-26 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#ifndef ST_IS_LatchingRelaySwitch_H
#define ST_IS_LatchingRelaySwitch_H
#include "InterruptSensor.h"
namespace st
{
class IS_LatchingRelaySwitch : public InterruptSensor //inherits from parent InterruptSensor Class
{
private:
//following are for the digital output
bool m_bCurrentState; //HIGH or LOW
bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic
byte m_nOutputPin1; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
byte m_nOutputPin2; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
unsigned long m_lOutput1Time; //number of milliseconds to keep digital output HIGH before automatically turning off
unsigned long m_lOutput2Time; //number of milliseconds to keep digital output HIGH before automatically turning off
unsigned long m_lTimeChanged; //time when the digital output was last changed
bool m_bTimerPending; //true if waiting on relay timer to expire
void writeStateToPin(byte, bool); //function to update the Arduino Digital Output Pin
public:
//constructor - called in your sketch's global variable declaration section
IS_LatchingRelaySwitch(const __FlashStringHelper *name, byte pinInput, bool iState, bool internalPullup, long numReqCounts, byte pinOutput1, byte pinOutput2, bool startingState = LOW, bool invertLogic = false, unsigned long Output1Time = 1000, unsigned long Output2Time = 1000, bool initializeOutputs = false);
//destructor
virtual ~IS_LatchingRelaySwitch();
//initialization function
virtual void init();
//update function
void update();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output)
virtual void beSmart(const String &str);
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
//gets
//virtual byte getPin() const { return m_nOutputPin; }
virtual bool getTimerActive() const { return m_bTimerPending; }
virtual bool getStatus() const { return m_bCurrentState; }
};
}
#endif

View File

@@ -0,0 +1,118 @@
//******************************************************************************************
// File: IS_Motion.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Motion is a class which implements the SmartThings "Motion Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Motion sensor5(F("motion1"), PIN_MOTION, HIGH, false, 500);
//
// st::IS_Motion() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
// - long inactiveTimeout - OPTIONAL - number of milliseconds motion must be inactive before sending update to hub (default = 0)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2016-09-03 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2017-01-25 Dan Ogorchock Corrected issue with INPUT_PULLUP per request of Jiri Culik
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2020-01-31 Dan Ogorchock Added optional inactivity timeout
//
//
//******************************************************************************************
#include "IS_Motion.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor
IS_Motion::IS_Motion(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts, long inactiveTimeout) :
InterruptSensor(name, pin, iState, pullup, numReqCounts), //use parent class' constructor
calibrated(false),
m_inactiveTimeout(inactiveTimeout),
m_inactiveTimerRunning(false)
{
}
//destructor
IS_Motion::~IS_Motion()
{
}
void IS_Motion::init()
{
if (debug){
Serial.println(F("IS_Motion: 30 second Motion Sensor Calibration Started..."));
}
//calibrate the PIR Motion Sensor
digitalWrite(getInterruptPin(), LOW);
timer=millis();
//delay(30000);
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the motion sensor
void IS_Motion::refresh()
{
Everything::sendSmartString(getName() + (getStatus() ? F(" active") : F(" inactive")));
}
void IS_Motion::runInterrupt()
{
if (m_inactiveTimerRunning == false) {
//add the "active" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" active"));
}
//cancel any inactivity timer that may be running
m_inactiveTimerRunning = false;
}
void IS_Motion::runInterruptEnded()
{
//start inactivity timer
m_inactiveTimer = millis();
m_inactiveTimerRunning = true;
}
void IS_Motion::update()
{
if (calibrated) {
InterruptSensor::update();
if ((m_inactiveTimerRunning == true) && (millis() > m_inactiveTimer + m_inactiveTimeout)) {
m_inactiveTimerRunning = false;
//add the "inactive" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" inactive"));
}
}
else
if(millis()>timer+30000)
{
calibrated=true;
//get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here!
setInterruptPin(getInterruptPin());
InterruptSensor::init();
if (debug)
{
Serial.println(F("IS_Motion: Motion Sensor Calibration Finished"));
}
}
}
}

View File

@@ -0,0 +1,76 @@
//******************************************************************************************
// File: IS_Motion.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Motion is a class which implements the SmartThings "Motion Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Motion sensor5(F("motion1"), PIN_MOTION, HIGH, false, 500);
//
// st::IS_Motion() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
// - long inactiveTimeout - OPTIONAL - number of milliseconds motion must be inactive before sending update to hub (default = 0)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2016-09-03 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2017-01-25 Dan Ogorchock Corrected issue with INPUT_PULLUP per request of Jiri Culik
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2020-01-31 Dan Ogorchock Added optional inactivity timeout
//
//
//******************************************************************************************
#ifndef ST_IS_MOTION_H
#define ST_IS_MOTION_H
#include "InterruptSensor.h"
namespace st
{
class IS_Motion: public InterruptSensor
{
private:
//inherits everything necessary from parent InterruptSensor Class
long timer;
bool calibrated;
long m_inactiveTimeout;
bool m_inactiveTimerRunning;
long m_inactiveTimer;
public:
//constructor - called in your sketch's global variable declaration section
IS_Motion(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0, long inactiveTimeout = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0)
//destructor
virtual ~IS_Motion();
//initialization function
virtual void init();
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the motion sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
//override update method
virtual void update();
};
}
#endif

View File

@@ -0,0 +1,72 @@
//******************************************************************************************
// File: IS_Presence.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Presence is a class which implements the SmartThings "Presence Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Presence sensor1(F("presence1"), PIN_PRESENCE, LOW, true, 5000);
//
// st::IS_Presence() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-10-12 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#include "IS_Presence.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor
IS_Presence::IS_Presence(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup, long numReqCounts) :
InterruptSensor(name, pin, iState, internalPullup, numReqCounts) //use parent class' constructor
{
}
//destructor
IS_Presence::~IS_Presence()
{
}
void IS_Presence::init()
{
//get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the presence sensor
void IS_Presence::refresh()
{
Everything::sendSmartString(getName() + (getStatus() ? F(" present") : F(" notpresent")));
}
void IS_Presence::runInterrupt()
{
//add the "present" event to the buffer to be queued for transfer to Hubitat/SmartThings
Everything::sendSmartString(getName() + F(" present"));
}
void IS_Presence::runInterruptEnded()
{
//add the "notpresent" event to the buffer to be queued for transfer to Hubitat/SmartThings
Everything::sendSmartString(getName() + F(" notpresent"));
}
}

View File

@@ -0,0 +1,62 @@
//******************************************************************************************
// File: IS_Presence.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Presence is a class which implements the SmartThings "Presence Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Presence sensor1(F("presence1"), PIN_PRESENCE, LOW, true, 5000);
//
// st::IS_Presence() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-10-12 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#ifndef ST_IS_PRESENCE_H
#define ST_IS_PRESENCE_H
#include "InterruptSensor.h"
namespace st
{
class IS_Presence: public InterruptSensor
{
private:
//inherits everything necessary from parent InterruptSensor Class
public:
//constructor - called in your sketch's global variable declaration section
IS_Presence(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0)
//destructor
virtual ~IS_Presence();
//initialization function
virtual void init();
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the presence sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
};
}
#endif

View File

@@ -0,0 +1,75 @@
//******************************************************************************************
// File: IS_Smoke.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Smoke is a class which implements the SmartThings "Smoke Detector" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: static st::IS_Smoke sensor6(F("smoke1"), PIN_SMOKE, HIGH, false, 500);
//
// st::IS_Smoke() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2019-11-04 Dan Ogorchock Updated Comments
//
//
//******************************************************************************************
#include "IS_Smoke.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor
IS_Smoke::IS_Smoke(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts) :
InterruptSensor(name, pin, iState, pullup, numReqCounts) //use parent class' constructor
{
}
//destructor
IS_Smoke::~IS_Smoke()
{
}
void IS_Smoke::init()
{
//get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
void IS_Smoke::refresh()
{
Everything::sendSmartString(getName() + (getStatus() ? F(" clear") : F(" detected")));
}
void IS_Smoke::runInterrupt()
{
//add the "closed" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" clear"));
}
void IS_Smoke::runInterruptEnded()
{
//add the "open" event to the buffer to be queued for transfer to the ST Shield
Everything::sendSmartString(getName() + F(" detected"));
}
}

View File

@@ -0,0 +1,65 @@
//******************************************************************************************
// File: IS_Smoke.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Smoke is a class which implements the SmartThings "Smoke Detector" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: static st::IS_Smoke sensor6(F("smoke1"), PIN_SMOKE, HIGH, false, 500);
//
// st::IS_Smoke() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2019-11-04 Dan Ogorchock Updated Comments
//
//
//******************************************************************************************
#ifndef ST_IS_SMOKE_H
#define ST_IS_SMOKE_H
#include "InterruptSensor.h"
namespace st
{
class IS_Smoke: public InterruptSensor
{
private:
//inherits everything necessary from parent InterruptSensor Class
public:
//constructor - called in your sketch's global variable declaration section
IS_Smoke(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0)
//destructor
virtual ~IS_Smoke();
//initialization function
virtual void init();
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
};
}
#endif

View File

@@ -0,0 +1,73 @@
//******************************************************************************************
// File: IS_Water.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Water is a class which implements the Hubitat "Water Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Water sensor6(F("water1"), PIN_WATER, HIGH, true, 500);
//
// st::IS_Water() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2020-06-30 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#include "IS_Water.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor
IS_Water::IS_Water(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup, long numReqCounts) :
InterruptSensor(name, pin, iState, internalPullup, numReqCounts) //use parent class' constructor
{
}
//destructor
IS_Water::~IS_Water()
{
}
void IS_Water::init()
{
//get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here!
InterruptSensor::init();
}
//called periodically by Everything class to ensure the Hub is kept consistent with the state of the water sensor
void IS_Water::refresh()
{
Everything::sendSmartString(getName() + (getStatus() ? F(" wet") : F(" dry")));
}
void IS_Water::runInterrupt()
{
//add the "closed" event to the buffer to be queued for transfer to the hub
Everything::sendSmartString(getName() + F(" wet"));
}
void IS_Water::runInterruptEnded()
{
//add the "open" event to the buffer to be queued for transfer to the hub
Everything::sendSmartString(getName() + F(" dry"));
}
}

View File

@@ -0,0 +1,62 @@
//******************************************************************************************
// File: IS_Water.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: IS_Water is a class which implements the Hubitat "Water Sensor" device capability.
// It inherits from the st::InterruptSensor class.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::IS_Water sensor6(F("water1"), PIN_WATER, HIGH, true, 500);
//
// st::IS_Water() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input
// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true
// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP
// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms)
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2020-06-30 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#ifndef ST_IS_WATER_H
#define ST_IS_WATER_H
#include "InterruptSensor.h"
namespace st
{
class IS_Water: public InterruptSensor
{
private:
//inherits everything necessary from parent InterruptSensor Class
public:
//constructor - called in your sketch's global variable declaration section
IS_Water(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0)
//destructor
virtual ~IS_Water();
//initialization function
virtual void init();
//called periodically by Everything class to ensure the Hub is kept consistent with the state of the water sensor
virtual void refresh();
//handles what to do when interrupt is triggered
virtual void runInterrupt();
//handles what to do when interrupt is ended
virtual void runInterruptEnded();
};
}
#endif

View File

@@ -0,0 +1,151 @@
//******************************************************************************************
// File: InterruptSensor.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::InterruptSensor is a generic class which inherits from st::Sensor. This is the
// parent class for the st::IS_Motion, IS_Contact, and IS_DoorControl classes.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-03-17 Dan Added optional "numReqCounts" constructor argument/capability
// 2019-09-22 Dan Ogorchock ESP8266 support for using A0 pin as a digital input
//
//
//******************************************************************************************
#include "InterruptSensor.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//Checks to see if the pin has changed state. If so calls appropriate function.
void InterruptSensor::checkIfTriggered()
{
bool inputState;
#if defined(ARDUINO_ARCH_ESP8266)
if (m_nInterruptPin == A0)
{
if (m_nLoopCounter == 1000) { //reading an analog input every pass through loop() is too slow
inputState = analogRead(A0) > 512 ? HIGH : LOW;
m_nLoopCounter = 0;
}
else {
m_nLoopCounter++;
return;
}
}
else {
inputState = digitalRead(m_nInterruptPin);
}
#else
inputState = digitalRead(m_nInterruptPin);
#endif
if (inputState == m_bInterruptState && !m_bStatus) //new interrupt
{
m_nCurrentDownCount = m_nRequiredCounts;
m_nCurrentUpCount++;
if (m_nCurrentUpCount >= m_nRequiredCounts)
{
m_bStatus = true;
m_bInitRequired = false;
runInterrupt();
}
}
else if ((inputState != m_bInterruptState && m_bStatus) || m_bInitRequired) //interrupt has ended OR Init called us
{
m_nCurrentUpCount = 0;
m_nCurrentDownCount--;
if (m_nCurrentDownCount <= 0)
{
m_bStatus = false;
m_bInitRequired = false;
runInterruptEnded();
}
}
}
//public
//constructor
InterruptSensor::InterruptSensor(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts) :
Sensor(name),
m_bInterruptState(iState),
m_bStatus(false),
m_bPullup(pullup),
m_bInitRequired(true),
m_nRequiredCounts(numReqCounts),
m_nCurrentUpCount(0),
m_nCurrentDownCount(numReqCounts),
m_nLoopCounter(0)
{
setInterruptPin(pin);
}
//destructor
InterruptSensor::~InterruptSensor()
{
}
//initialization function
void InterruptSensor::init()
{
checkIfTriggered();
}
//update function
void InterruptSensor::update()
{
checkIfTriggered();
}
//handles start of an interrupt - all derived classes should implement this virtual function
void InterruptSensor::runInterrupt()
{
if(debug)
{
Everything::sendSmartString(getName()+F(" triggered ") + (m_bInterruptState?F("HIGH"):F("LOW)")));
}
}
//handles the end of an interrupt - all derived classes should implement this virtual function
void InterruptSensor::runInterruptEnded()
{
if(debug)
{
Everything::sendSmartString(getName()+F(" ended ") + (m_bInterruptState?F("LOW)"):F("HIGH)")));
}
}
//sets the pin to be monitored, and set the Arduino pinMode based on constructor data
void InterruptSensor::setInterruptPin(byte pin)
{
m_nInterruptPin=pin;
#if defined(ARDUINO_ARCH_ESP8266)
if (pin == A0)
{
pinMode(m_nInterruptPin, INPUT);
return;
}
#endif
if(!m_bPullup)
{
pinMode(m_nInterruptPin, INPUT);
}
else
{
pinMode(m_nInterruptPin, INPUT_PULLUP);
}
}
//debug flag to determine if debug print statements are executed (set value in your sketch)
bool InterruptSensor::debug=false;
}

View File

@@ -0,0 +1,78 @@
//******************************************************************************************
// File: InterruptSensor.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::InterruptSensor is a generic class which inherits from st::Sensor. This is the
// parent class for the st::IS_Motion, IS_Contact, and IS_DoorControl classes.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-03-17 Dan Added optional "numReqCounts" constructor argument/capability
// 2019-09-22 Dan Ogorchock ESP8266 support for using A0 pin as a digital input
//
//
//******************************************************************************************
#ifndef ST_INTERRUPTSENSOR_H
#define ST_INTERRUPTSENSOR_H
#include "Sensor.h"
namespace st
{
class InterruptSensor: public Sensor
{
private:
byte m_nInterruptPin; //pin that will be monitored for change of state
bool m_bInterruptState; //LOW or HIGH - determines which value indicates the interrupt is true (i.e. LOW=Falling Edge, HIGH=Rising Edge)
bool m_bStatus; //true == interrupted
bool m_bPullup; //true == Internal Pullup resistor required, set in constructor call in your sketch
bool m_bInitRequired; //
long m_nRequiredCounts; //Number of required counts (checks of the pin) before believing the pin is high/low
long m_nCurrentUpCount;
long m_nCurrentDownCount;
long m_nLoopCounter;
void checkIfTriggered();
public:
//constructor
InterruptSensor(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup=false, long numReqCounts=0); //(defaults to NOT using internal pullup resistors, and required counts = 0)
//destructor
virtual ~InterruptSensor();
//initialization function
virtual void init();
//update function
virtual void update();
//handles what to do when interrupt is triggered - all derived classes should implement this virtual function
virtual void runInterrupt();
//handles what to do when interrupt is ended - all derived classes should implement this virtual function
virtual void runInterruptEnded();
//gets
inline byte getInterruptPin() const {return m_nInterruptPin;}
inline bool getInterruptState() const {return m_bInterruptState;}
inline bool getStatus() const {return m_bStatus;} //whether or not the device is currently interrupted
//sets
void setInterruptPin(byte pin);
void setInterruptState(bool b) {m_bInterruptState=b;}
//debug flag to determine if debug print statements are executed (set value in your sketch)
static bool debug;
};
}
#endif

View File

@@ -0,0 +1,136 @@
//******************************************************************************************
// File: PS_10kThermistor.cpp
// Authors: D. Johnson (_M2) based on the work of Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_10kThermistor is a class which implements the Hubitat "Temperature Measurement" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// value of a simple thermal resistor using another 10k resistor as a voltage divider.
//
// The last four arguments of the constructor are used as arguments to configure the resistance of the parts.
// The first number is the resistance of the thermistor. Second is R1. Third is the thermistor coefficient. Last is your preference of units.
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_10kThermistor sensor1(F("temperature1"), 120, 0, PIN_THERMISTOR, 10000, 10000, 3300, "F");
//
// st::PS_10kThermistor() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - int tl - OPTIONAL - resistance of the thermocouple at the nominal temperature (usually 25C, 77F)
// - int r1 - OPTIONAL - actual measured resistance of the voltage divider resistor
// - int BCOEFF - OPTIONAL - The beta coefficient of the thermistor (usually 3000-4000). Tweak this number to calibrate.
// - int tempNOM - OPTIONAL - The nominal temperature of the thermistor @10k (usually 25C, 77F).
// - int unit - OPTIONAL - Use the letter F for Farhenheit, C for Celsius
//
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2019-12-23 D. Johnson Created 10k_Thermistor using PS_Illuminance as example
//
//******************************************************************************************
#include "PS_10kThermistor.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor - called in your sketch's global variable declaration section
PS_10kThermistor::PS_10kThermistor(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int t1, int r1, int BCOEFF, int tempNom, char unit):
PollingSensor(name, interval, offset),
m_nSensorValue(0),
thermResistance(t1),
r1Resistance(r1),
BetaCoeff(BCOEFF),
UNIT(unit),
TEMPNOMINAL(tempNom)
{
setPin(analogInputPin);
}
//destructor
PS_10kThermistor::~PS_10kThermistor()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_10kThermistor::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_10kThermistor::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_10kThermistor::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_10kThermistor::getData()
{
int NUMSAMPLES = 10;
float samples[NUMSAMPLES];
for (int i=0; i< NUMSAMPLES; i++)
{
samples[i] = analogRead(m_nAnalogInputPin);
}
// average all the samples out
float average = 0;
for (int i=0; i< NUMSAMPLES; i++)
{
average += samples[i];
}
average /= NUMSAMPLES;
// convert the value to resistance
average = 1023 / average - 1;
average = r1Resistance / average;
float reading;
float Temp1F;
float Temp1C;
reading = average / thermResistance; // (R/Ro)
reading = log(reading); // ln(R/Ro)
reading /= BetaCoeff; // 1/B * ln(R/Ro)
reading += 1.0 / (TEMPNOMINAL + 273.15); // + (1/To)
reading = 1.0 / reading; // Invert
Temp1C = reading -= 273.15; // convert to C
Temp1F = (Temp1C * 1.8) + 32; // convert to F
if(UNIT == 'F'){
m_nSensorValue = Temp1F;
}
else {
m_nSensorValue = Temp1C;
}
Everything::sendSmartString(getName() + " " + String(m_nSensorValue));
}
void PS_10kThermistor::setPin(byte pin)
{
m_nAnalogInputPin = pin;
}
}

View File

@@ -0,0 +1,76 @@
//******************************************************************************************
// File: PS_10kThermistor.cpp
// Authors: D. Johnson (_M2) based on the work of Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_10kThermistor is a class which implements the Hubitat "Temperature Measurement" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// value of a simple thermal resistor using another 10k resistor as a voltage divider.
//
// The last four arguments of the constructor are used as arguments to configure the resistance of the parts.
// The first number is the resistance of the thermistor. Second is R1. Third is the thermistor coefficient. Last is your preference of units.
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_10kThermistor sensor1(F("temperature1"), 120, 0, PIN_THERMISTOR, 10000, 10000, 3300, "F");
//
// st::PS_10kThermistor() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - int tl - OPTIONAL - resistance of the thermocouple at the nominal temperature (usually 25C, 77F)
// - int r1 - OPTIONAL - actual measured resistance of the voltage divider resistor
// - int BCOEFF - OPTIONAL - The beta coefficient of the thermistor (usually 3000-4000). Tweak this number to calibrate.
// - int tempNOM - OPTIONAL - The nominal temperature of the thermistor @10k (usually 25C, 77F).
// - int unit - OPTIONAL - Use the letter F for Farhenheit, C for Celsius
//
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2019-12-23 D. Johnson Created 10k_Thermistor using PS_Illuminance as example
//
//******************************************************************************************
#ifndef ST_PS_10KTHERMISTOR_H
#define ST_PS_10KTHERMISTOR_H
#include "PollingSensor.h"
namespace st
{
class PS_10kThermistor: public PollingSensor
{
private:
byte m_nAnalogInputPin;
float m_nSensorValue;
int thermResistance;
int r1Resistance;
int BetaCoeff;
int TEMPNOMINAL;
char UNIT;
public:
//constructor - called in your sketch's global variable declaration section
PS_10kThermistor(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int t1=10000, int r1=10000, int BCOEFF=3300, int tempNom=25, char unit='F');
//destructor
virtual ~PS_10kThermistor();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nAnalogInputPin;}
inline byte getSensorValue() const {return m_nSensorValue;}
//sets
void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,118 @@
//******************************************************************************************
// File: PS_Generic.h
// Authors: Allan (vseven) (Based on original programming by Dan G Ogorchock & Daniel J Ogorchock (Father and Son) )
//
// Summary: PS_Generic is a class which implements only the SmartThings "Sensor" device capability.
// It inherits from the st::PollingSensor class. The current version is made to be used as a framework
// for more complicated programming
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Generic sensor1(F("generic1"), 120, 0);
//
// st::PS_Generic() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2017-10-20 Allan (vseven) Modified original PS_Illuminance library for use with a generic sensor
// 2017-12-28 Dan Ogorchock Fixed bug with improper init() definition
//
//******************************************************************************************
#include "PS_Generic.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor - called in your sketch's global variable declaration section
//this can be modified to accepting more varialbes into it by modifying the
//next line. For example if you wanted to assign a pin or a variable you could add
//a ", myVariable" after the offset below and then use that within your program.
//you would need to also update the associated line in the header file.
PS_Generic::PS_Generic(const __FlashStringHelper *name, unsigned int interval, int offset):
PollingSensor(name, interval, offset),m_nSensorValue(0)
{
}
//destructor
PS_Generic::~PS_Generic()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_Generic::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_Generic::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_Generic::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
void PS_Generic::init() {
// This is where you would add any initialization for your custom code. For example if you
// are using a Adafruit sensor this is where you would setup the sensor.
Serial.println("Initiating the generic class.");
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_Generic::getData()
{
Serial.println("getData routine called");
// Here is where you would do whatever you need to do to get your data. Some basic
// sample data is provided below just to see values come back in SmartThings. We firt
// define a integer called someValue then assign it a value of 15.
uint16_t someValue;
someValue = 15;
// Here is where you would assign the data to the sensor value. m_nSensorValue is a
// ST_Anything standard for the value of the sensor, in this case our generic sensor.
// In this example I'm converting everything to a String to make it easier to use if
// you are trying to send up multiple values. For example you can add the values together
// as a tring with a colon seperating them then in the DTH split the values back out.
String m_nSensorValue = String(someValue, DEC);
// To make it easier to debug print out our name and sensor value before sending it
Serial.println(getName());
Serial.println(m_nSensorValue);
// Send the value to our parent which will then update the device handler
Everything::sendSmartString(getName() + " " + String(m_nSensorValue));
}
}

View File

@@ -0,0 +1,71 @@
//******************************************************************************************
// File: PS_Generic.h
// Authors: Allan (vseven) (Based on original programming by Dan G Ogorchock & Daniel J Ogorchock (Father and Son) )
//
// Summary: PS_Generic is a class which implements only the SmartThings "Sensor" device capability.
// It inherits from the st::PollingSensor class. The current version is made to be used as a framework
// for more complicated programming
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Generic sensor1(F("generic1"), 120, 0);
//
// st::PS_Generic() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2017-10-20 Allan (vseven) Modified original PS_Illuminance library for use with a generic sensor
// 2017-12-28 Dan Ogorchock Fixed bug with improper init() definition
//
//
//******************************************************************************************
#include "PollingSensor.h"
namespace st
{
class PS_Generic: public PollingSensor
{
private:
char m_nSensorValue; //converted to a string so all data can be passed in one call
public:
//constructor - called in your sketch's global variable declaration section
//this can be modified to accepting more varialbes into it by modifying the
//line. For example if you wanted to assign a pin or a variable you could add
//a ", int myVariable" after the offset below and then use that within your program.
//you would need to also update the associated line in the .cpp file.
PS_Generic(const __FlashStringHelper *name, unsigned int interval, int offset);
//destructor
virtual ~PS_Generic();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//initialization routine
virtual void init();
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getSensorValue() const {return m_nSensorValue;}
//sets
};
}

View File

@@ -0,0 +1,105 @@
//******************************************************************************************
// File: PS_Illuminance.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// value of a simple photo resistor.
//
// The last four arguments of the constructor are used as arguments to an Arduino map() function which
// is used to scale the analog input readings (0 to 1024) to Lux before sending to SmartThings. The
// defaults for this sensor are based on the device used during testing.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Illuminance sensor1(F("illuminance1"), 120, 0, PIN_ILLUMINANCE, 0, 1023, 0, 1000);
//
// st::PS_Illuminance() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - int s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
// - int s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
// - int m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
// - int m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#include "PS_Illuminance.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor - called in your sketch's global variable declaration section
PS_Illuminance::PS_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int s_l, int s_h, int m_l, int m_h):
PollingSensor(name, interval, offset),
m_nSensorValue(0),
SENSOR_LOW(s_l),
SENSOR_HIGH(s_h),
MAPPED_LOW(m_l),
MAPPED_HIGH(m_h)
{
setPin(analogInputPin);
}
//destructor
PS_Illuminance::~PS_Illuminance()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_Illuminance::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_Illuminance::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_Illuminance::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_Illuminance::getData()
{
int m_nSensorValue=map(analogRead(m_nAnalogInputPin), SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH);
Everything::sendSmartString(getName() + " " + String(m_nSensorValue));
}
void PS_Illuminance::setPin(byte pin)
{
m_nAnalogInputPin=pin;
}
}

View File

@@ -0,0 +1,77 @@
//******************************************************************************************
// File: PS_Illuminance.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// value of a simple photo resistor.
//
// The last four arguments of the constructor are used as arguments to an Arduino map() function which
// is used to scale the analog input readings (0 to 1024) to Lux before sending to SmartThings. The
// defaults for this sensor are based on the device used during testing.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Illuminance sensor1(F("illuminance1"), 120, 0, PIN_ILLUMINANCE, 0, 1023, 0, 1000);
//
// st::PS_Illuminance() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - int s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
// - int s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
// - int m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
// - int m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
//
//
//******************************************************************************************
#ifndef ST_PS_ILLUMINANCE_H
#define ST_PS_ILLUMINANCE_H
#include "PollingSensor.h"
namespace st
{
class PS_Illuminance: public PollingSensor
{
private:
byte m_nAnalogInputPin;
int m_nSensorValue;
const int SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH;
public:
//constructor - called in your sketch's global variable declaration section
PS_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int s_l=0, int s_h=1023, int m_l=1000, int m_h=0);
//destructor
virtual ~PS_Illuminance();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nAnalogInputPin;}
inline byte getSensorValue() const {return m_nSensorValue;}
//sets
void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,103 @@
//******************************************************************************************
// File: PS_MQ2_Smoke.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_MQ2_Smoke is a class which implements the SmartThings "Smoke Detector" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// value from the MQ2 sensor.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_MQ2_Smoke sensor1("smoke1", 10, 0, PIN_MQ2_SMOKE, 300);
//
// st::PS_MQ2_Smoke() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name e.g. "smoke1", "smoke2", etc...
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - int sensorLimit - REQUIRED - if sensor reads value above this limit, report Smoke Detected (typical range is 0 to 1023 on Arduino Analog Input)
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the Arduino. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2017-07-04 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#include "PS_MQ2_Smoke.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor - called in your sketch's global variable declaration section
PS_MQ2_Smoke::PS_MQ2_Smoke(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int sensorLimit):
PollingSensor(name, interval, offset),
m_nSensorValue(0),
m_nSensorLimit(sensorLimit)
{
setPin(analogInputPin);
}
//destructor
PS_MQ2_Smoke::~PS_MQ2_Smoke()
{
}
//SmartThings data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_MQ2_Smoke::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_MQ2_Smoke::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_MQ2_Smoke::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_MQ2_Smoke::getData()
{
int m_nSensorValue=analogRead(m_nAnalogInputPin);
Everything::sendSmartString(getName() + (m_nSensorValue < m_nSensorLimit ? F(" clear") : F(" detected")));
if (st::PollingSensor::debug)
{
Serial.print(F("PS_MQ2_Smoke::Analog Pin value is "));
Serial.print(m_nSensorValue);
Serial.print(F(" vs limit of "));
Serial.println(m_nSensorLimit);
}
}
void PS_MQ2_Smoke::setPin(byte pin)
{
m_nAnalogInputPin=pin;
}
}

View File

@@ -0,0 +1,69 @@
//******************************************************************************************
// File: PS_MQ2_Smoke.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_MQ2_Smoke is a class which implements the SmartThings "Smoke Detector" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// value from the MQ2 sensor.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_MQ2_Smoke sensor1("smoke1", 10, 0, PIN_MQ2_SMOKE, 300);
//
// st::PS_MQ2_Smoke() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name e.g. "smoke1", "smoke2", etc...
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output
// - int sensorLimit - REQUIRED - if sensor reads value above this limit, report Smoke Detected (typical range is 0 to 1023 on Arduino Analog Input)
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the Arduino. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2017-07-04 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#ifndef ST_PS_MQ2_SMOKE_H
#define ST_PS_MQ2_SMOKE_H
#include "PollingSensor.h"
namespace st
{
class PS_MQ2_Smoke: public PollingSensor
{
private:
byte m_nAnalogInputPin;
int m_nSensorValue;
int m_nSensorLimit;
public:
//constructor - called in your sketch's global variable declaration section
PS_MQ2_Smoke(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int sensorLimit);
//destructor
virtual ~PS_MQ2_Smoke();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nAnalogInputPin;}
inline byte getSensorValue() const {return m_nSensorValue;}
//sets
void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,138 @@
//******************************************************************************************
// File: PS_Power.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Power is a class which implements the SmartThings "Power Meter" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// voltage on an analog input pin via the EmonLib. This produce the Irms current of the Current Transformer.
// The Irms current is then multiplied by the voltage constant passed in to produce Power in Watts.
//
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Power sensor1(F("power1"), 120, 0, PIN_POWER, 30.0, 1480, 120.0);
//
// st::PS_Power() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double ICAL - REQUIRED - EmonLib Calibration Constant
// - unsigned int numSamples - OPTIONAL - defaults to 1480, number of analog readings to use for calculating the Irms Current
// - float voltage - OPTIONAL - defaults to 120, AC voltage of the mains line being monitored
// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-02-17 Dan Ogorchock Original Creation
// 2019-09-19 Dan Ogorchock Added filtering optional argument to help reduce noisy signals
//
//
//******************************************************************************************
#include "PS_Power.h"
#include "Constants.h"
#include "Everything.h"
#include <math.h>
namespace st
{
//private
//public
//constructor - called in your sketch's global variable declaration section
PS_Power::PS_Power(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double ICAL, unsigned int NumSamples, float voltage, byte filterConstant) :
PollingSensor(name, interval, offset),
emon1(),
m_nAnalogInputPin(analogInputPin),
m_fICAL(ICAL),
m_fIrms(0.0),
m_fApparentPower(0.0),
m_nNumSamples(NumSamples),
m_fVoltage(voltage)
{
setPin(analogInputPin);
//check for upper and lower limit and adjust accordingly
if ((filterConstant <= 0) || (filterConstant >= 100))
{
m_fFilterConstant = 1.0;
}
else if (filterConstant <= 5)
{
m_fFilterConstant = 0.05;
}
else
{
m_fFilterConstant = float(filterConstant) / 100;
}
emon1.current(m_nAnalogInputPin, m_fICAL); // Current: input pin, calibration.
}
//destructor
PS_Power::~PS_Power()
{
}
void PS_Power::init()
{
//Make sure the EmonLib has some data accumulated before anything is transmitted to ST/Hubitat
m_fIrms = emon1.calcIrms(m_nNumSamples);
m_fIrms = emon1.calcIrms(m_nNumSamples);
m_fIrms = emon1.calcIrms(m_nNumSamples);
m_fIrms = emon1.calcIrms(m_nNumSamples);
m_fIrms = emon1.calcIrms(m_nNumSamples);
m_fApparentPower = m_fIrms * m_fVoltage; //Calcuate Apparent Power
//Send initial data to ST/Hubitat
getData();
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_Power::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_Power::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_Power::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
//function to get data from sensor and queue results for transfer to ST/Hubitat
void PS_Power::getData()
{
double tempValue = 0;
m_fIrms = emon1.calcIrms(m_nNumSamples); // Calculate Irms only
tempValue = m_fIrms * m_fVoltage; //Calcuate Apparent Power
m_fApparentPower = (m_fFilterConstant * tempValue) + (1 - m_fFilterConstant) * m_fApparentPower;
Everything::sendSmartString(getName() + " " + String(m_fApparentPower));
}
void PS_Power::setPin(byte pin)
{
m_nAnalogInputPin=pin;
}
}

View File

@@ -0,0 +1,79 @@
//******************************************************************************************
// File: PS_Power.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Power is a class which implements the SmartThings "Power Meter" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// voltage on an analog input pin via the EmonLib. This produce the Irms current of the Current Transformer.
// The Irms current is then multiplied by the voltage constant passed in to produce Power in Watts.
//
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Power sensor1(F("power1"), 120, 0, PIN_POWER, 30.0, 1480, 120.0);
//
// st::PS_Power() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double ICAL - REQUIRED - EmonLib Calibration Constant
// - unsigned int numSamples - OPTIONAL - defaults to 1480, number of analog readings to use for calculating the Irms Current
// - float voltage - OPTIONAL - defaults to 120, AC voltage of the mains line being monitored
// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-02-17 Dan Ogorchock Original Creation
// 2019-09-19 Dan Ogorchock Added filtering optional argument to help reduce noisy signals
//
//
//******************************************************************************************
#ifndef ST_PS_Power_H
#define ST_PS_Power_H
#include <EmonLib.h>
#include "PollingSensor.h"
namespace st
{
class PS_Power: public PollingSensor
{
private:
EnergyMonitor emon1;
byte m_nAnalogInputPin;
double m_fICAL;
unsigned int m_nNumSamples;
float m_fVoltage;
double m_fIrms;
double m_fApparentPower;
float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00
public:
//constructor - called in your sketch's global variable declaration section
PS_Power(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double ICAL, unsigned int NumSamples=1480, float voltage=120.0, byte filterConstant = 100);
//destructor
virtual ~PS_Power();
//initialization function
virtual void init();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nAnalogInputPin;}
inline float getSensorValue() const {return m_fApparentPower;}
//sets
void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,151 @@
//******************************************************************************************
// File: PS_PulseCounter.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_PulseCounter is a class which implements the SmartThings "Power Meter"-style device capability.
// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the
// the number of counts between polling intervals. At the polling interval, the pulse count is converted
// to engineering units via a linear conversion (engUnits = slope x counts + offset).
//
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_PulseCounter sensor3(F("power1"), 60, 5, PIN_PULSE, FALLING, INPUT_PULLUP, 1.0, 0);
//
// st::PS_PulseCounter() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must be in form of "power1", "power2", etc...
// - int interval - REQUIRED - the polling interval in seconds
// - int offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the GPIO Pin to be used as an digital input (Hardware Interrupt)
// - byte inttype - REQUIRED - which type of Arduino interrupt to trigger the ISR (RISING, FALLING, CHANGE)
// - byte inputmode - REQUIRED - Mode of the digital input Pin (INPUT, INPUT_PULLUP)
// - float cnvslope - REQUIRED - Conversion to Engineering Units Slope
// - float cnvoffset - REQUIRED - Conversion to Engineering Units Offset
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-03-31 Dan Ogorchock Original Creation
// 2018-03-03 Dan Ogorchock Improved code to make generic for all boards, not just Arduino MEGA
// 2020-01-17 Dan Ogorchock Improved support for ESP8266 using Arduino IDE Board Manager 2.5.1 and newer
// 2020-11-15 Dan Ogorchock Prevent Refresh from sending data for this particular device.
// 2021-04-12 Dan Ogorchock Corrected data type for interrupt type to correct compiler error for Nano 33 IoT
// 2021-06-14 Dan Ogorchock Fixed for SAMD Architectures...again
// 2023-01-25 Dan Ogorchock Fixed for MKR 1010 (use PinStatus instead of int for inttype)
// 2023-01-26 Dan Ogorchock Fixed for SAMD Architecture boards versus all other boards
//
//
//******************************************************************************************
#include "PS_PulseCounter.h"
#include "Constants.h"
#include "Everything.h"
//#include "PinChangeInt.h"
namespace st
{
//private
//This "Counts" variables must be declared here so they can be used in the Interrupt Service Routines (ISR)
volatile unsigned long m_nCounts; //current count of interrupts (pulses)
//These are the four Interrupt Service Routines (ISR) which must be unique for each interrupt
#if defined(ARDUINO_ARCH_ESP8266)
void ICACHE_RAM_ATTR isrPulse() {
#else
void isrPulse() {
#endif
m_nCounts++;
}
//public
//constructor - called in your sketch's global variable declaration section
#if defined(ARDUINO_ARCH_SAMD)
PS_PulseCounter::PS_PulseCounter(const __FlashStringHelper *name, unsigned int interval, int offset, byte inputpin, PinStatus inttype, byte inputmode, float cnvslope, float cnvoffset) :
#else
PS_PulseCounter::PS_PulseCounter(const __FlashStringHelper* name, unsigned int interval, int offset, byte inputpin, int inttype, byte inputmode, float cnvslope, float cnvoffset) :
#endif
PollingSensor(name, interval, offset),
m_nInputMode(inputmode),
m_nSensorValue(0),
m_fCnvSlope(cnvslope),
m_fCnvOffset(cnvoffset)
{
setPin(inputpin);
m_nCounts = 0;
m_pCounter = &m_nCounts;
attachInterrupt(digitalPinToInterrupt(m_nInputPin), isrPulse, inttype);
}
//destructor
PS_PulseCounter::~PS_PulseCounter()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_PulseCounter::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_PulseCounter::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_PulseCounter::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
void PS_PulseCounter::refresh()
{
//This specific device should not report data except during its scheduled polling interval to preserve data integrity of the pulse counted value
//getData();
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_PulseCounter::getData()
{
if (m_pCounter)
{
noInterrupts();
unsigned long tmpCounts = *m_pCounter;
*m_pCounter = 0;
interrupts();
m_nSensorValue = long(m_fCnvSlope * tmpCounts + m_fCnvOffset);
}
else //invalid Pin/Interrupt was requested, therefore we are in an error condition
{
m_nSensorValue = 0;
if (st::PollingSensor::debug) {
Serial.println(F("PS_PulseCounter::Something went wrong. Need to debug."));
}
}
Everything::sendSmartString(getName() + " " + m_nSensorValue);
}
void PS_PulseCounter::setPin(byte pin)
{
m_nInputPin = pin;
pinMode(m_nInputPin, m_nInputMode);
}
}

View File

@@ -0,0 +1,99 @@
//******************************************************************************************
// File: PS_PulseCounter.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_PulseCounter is a class which implements the SmartThings "Power Meter"-style device capability.
// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the
// the number of counts between polling intervals. At the polling interval, the pulse count is converted
// to engineering units via a linear conversion (engUnits = slope x counts + offset).
//
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_PulseCounter sensor3(F("power1"), 60, 5, PIN_PULSE, FALLING, INPUT_PULLUP, 1.0, 0);
//
// st::PS_PulseCounter() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must be in form of "power1", "power2", etc...
// - int interval - REQUIRED - the polling interval in seconds
// - int offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the GPIO Pin to be used as an digital input (Hardware Interrupt)
// - byte inttype - REQUIRED - which type of Arduino interrupt to trigger the ISR (RISING, FALLING, CHANGE)
// - byte inputmode - REQUIRED - Mode of the digital input Pin (INPUT, INPUT_PULLUP)
// - float cnvslope - REQUIRED - Conversion to Engineering Units Slope
// - float cnvoffset - REQUIRED - Conversion to Engineering Units Offset
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-03-31 Dan Ogorchock Original Creation
// 2018-03-03 Dan Ogorchock Improved code to make generic for all boards, not just Arduino MEGA
// 2020-01-17 Dan Ogorchock Improved support for ESP8266 using Arduino IDE Board Manager 2.5.1 and newer
// 2020-11-15 Dan Ogorchock Prevent Refresh from sending data for this particular device.
// 2021-04-12 Dan Ogorchock Corrected data type for interrupt type to correct compiler error for Nano 33 IoT
// 2021-06-14 Dan Ogorchock Fixed for SAMD Architectures...again
// 2023-01-25 Dan Ogorchock Fixed for MKR 1010 (use PinStatus instead of int for inttype)
// 2023-01-26 Dan Ogorchock Fixed for SAMD Architecture boards versus all other boards
//
//
//******************************************************************************************
#ifndef ST_PS_PULSECOUNTER_H
#define ST_PS_PULSECOUNTER_H
#include "PollingSensor.h"
namespace st
{
class PS_PulseCounter : public PollingSensor
{
private:
byte m_nInputPin; //input pin connected to the pulse generator
byte m_nInputMode; //input mode (INPUT or INPUT_PULLUP)
unsigned long m_nSensorValue; //current sensor value (m_nSensorValue = Long(m_fCnvSlope * m_nCounts + m_fCnvOffset))
float m_fCnvSlope; //Linear Conversion Slope
float m_fCnvOffset; //Linear Conversion Offset
volatile unsigned long* m_pCounter; //Point to the correct Counter variable;
public:
#if defined(ARDUINO_ARCH_SAMD)
//constructor - called in your sketch's global variable declaration section
PS_PulseCounter(const __FlashStringHelper *name, unsigned int interval, int offset, byte inputpin, PinStatus inttype, byte inputmode, float cnvslope, float cnvoffset);
#else
//constructor - called in your sketch's global variable declaration section
PS_PulseCounter(const __FlashStringHelper* name, unsigned int interval, int offset, byte inputpin, int inttype, byte inputmode, float cnvslope, float cnvoffset);
#endif
//destructor
virtual ~PS_PulseCounter();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of each Device subclass object
virtual void refresh();
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nInputPin;}
inline long getSensorValue() const {return m_nSensorValue;}
//sets
void setPin(byte pin);
friend void isrPulse();
};
}
#endif

View File

@@ -0,0 +1,137 @@
//******************************************************************************************
// File: PS_SoundPressureLevel.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_SoundPressureLevel is a class which implements the "Sound Pressure Level" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// voltage on an anlog input pin and then scale it to engineering units.
//
// The last four arguments of the constructor are used as arguments to an Arduino map() function which
// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings.
//
// Create an instance of this class in your sketch's global variable section
// For Example: static st::PS_SoundPressureLevel sensor1(F("soundPressureLevel1"), 60, 0, PIN_SPL, 0, 1024, 0.0, 165.0, 50);
//
// st::PS_SoundPressureLevel() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value
// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value
// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting)
// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting)
// - long m_nHighSpeedPollingInterval - OPTIONAL - number of milliseconds between high speed analog reads - defaults to 50ms
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-07-08 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#include "PS_SoundPressureLevel.h"
#include "Constants.h"
#include "Everything.h"
#include <math.h>
namespace st
{
//private
float PS_SoundPressureLevel::map_double(double x, double in_min, double in_max, double out_min, double out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
//public
//constructor - called in your sketch's global variable declaration section
PS_SoundPressureLevel::PS_SoundPressureLevel(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, long HighSpeedPollingInterval):
PollingSensor(name, interval, offset),
m_fSensorValue(-1.0),
SENSOR_LOW(s_l),
SENSOR_HIGH(s_h),
MAPPED_LOW(m_l),
MAPPED_HIGH(m_h),
m_nHighSpeedPollingInterval(HighSpeedPollingInterval)
{
setPin(analogInputPin);
}
//destructor
PS_SoundPressureLevel::~PS_SoundPressureLevel()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_SoundPressureLevel::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_SoundPressureLevel::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_SoundPressureLevel::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
void PS_SoundPressureLevel::update()
{
//read the SPL value if enough time has elapsed
if ((millis() - m_nPrevMillis) > m_nHighSpeedPollingInterval) {
m_nPrevMillis = millis();
//read analog input
long tempAnalogInput = analogRead(m_nAnalogInputPin);
//scale raw AI value into Engineering Units
float tempValue = map_double(tempAnalogInput, SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH);
//if new value is greater than previous value, store the new value (i.e. keep the MAX SPL)
if (tempValue > m_fSensorValue) {
m_fSensorValue = tempValue;
}
}
//make sure to call the parent class' update function, since we've overriden update()
PollingSensor::update();
}
//function to get data from sensor and queue results for transfer to Hub
void PS_SoundPressureLevel::getData()
{
//make sure we have at least one reading before transferring data
update();
//transfer the data to the hub
Everything::sendSmartString(getName() + " " + String(m_fSensorValue));
//reset the max value
m_fSensorValue = -1.0;
}
void PS_SoundPressureLevel::setPin(byte pin)
{
m_nAnalogInputPin=pin;
}
}

View File

@@ -0,0 +1,82 @@
//******************************************************************************************
// File: PS_SoundPressureLevel.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_SoundPressureLevel is a class which implements the "Sound Pressure Level" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// voltage on an anlog input pin and then scale it to engineering units.
//
// The last four arguments of the constructor are used as arguments to an Arduino map() function which
// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings.
//
// Create an instance of this class in your sketch's global variable section
// For Example: static st::PS_SoundPressureLevel sensor1(F("soundPressureLevel1"), 60, 0, PIN_SPL, 0, 1024, 0.0, 165.0, 50);
//
// st::PS_SoundPressureLevel() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value
// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value
// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting)
// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting)
// - long m_nHighSpeedPollingInterval - OPTIONAL - number of milliseconds between high speed analog reads - defaults to 50ms
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2019-07-08 Dan Ogorchock Original Creation
//
//
//******************************************************************************************
#ifndef ST_PS_SOUNDPRESSURELEVEL_H
#define ST_PS_SOUNDPRESSURELEVEL_H
#include "PollingSensor.h"
namespace st
{
class PS_SoundPressureLevel: public PollingSensor
{
private:
byte m_nAnalogInputPin;
float m_fSensorValue;
double SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH;
long m_nPrevMillis;
long m_nHighSpeedPollingInterval;
float map_double(double x, double in_min, double in_max, double out_min, double out_max);
public:
//constructor - called in your sketch's global variable declaration section
PS_SoundPressureLevel(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l=0, double s_h=1024, double m_l=0.0, double m_h=165.0, long HighSpeedPollingInterval = 50);
//destructor
virtual ~PS_SoundPressureLevel();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//update function
virtual void update();
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nAnalogInputPin;}
inline float getSensorValue() const {return m_fSensorValue;}
//sets
void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,107 @@
//******************************************************************************************
// File: PS_Ultrasonic.cpp
// Authors:
//
// Summary: PS_Ultrasonic is a class which implements a custom Level device capability.
// It inherits from the st::PollingSensor class.
//
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Ultrasonic sensor1(F("ultrasonic1"), 60, 0, PIN_ULTRASONIC_T, PIN_ULTRASONIC_E);
//
// st::PS_Ultrasonic() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte digitalTriggerPin - REQUIRED - the Arduino Pin to be used as a digital output to trigger ultrasonic
// - byte digitalEchoPin - REQUIRED - the Arduino Pin to be used as a digital input to read the echo
//
//
// Change History:
//
// Date Who What
// ---- --- ----
//
//
//
//******************************************************************************************
#include "PS_Ultrasonic.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor - called in your sketch's global variable declaration section
PS_Ultrasonic::PS_Ultrasonic(const __FlashStringHelper *name, unsigned int interval, int offset, byte digitalTriggerPin, byte digitalEchoPin):
PollingSensor(name, interval, offset),
m_nSensorValue(0)
{
setPin(digitalTriggerPin,digitalEchoPin);
}
//destructor
PS_Ultrasonic::~PS_Ultrasonic()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_Ultrasonic::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
Serial.print("st string ##### ");
Serial.println(str);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_Ultrasonic::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_Ultrasonic::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_Ultrasonic::getData()
{
//int m_nSensorValue=map(analogRead(m_nAnalogInputPin), SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH);
long duration;
// Clears the trigPin
digitalWrite(m_nDigitalTriggerPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(m_nDigitalTriggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(m_nDigitalTriggerPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(m_nDigitalEchoPin, HIGH);
// Calculating the distance
m_nSensorValue = duration*0.034/2;
// queue the distance to send to smartthings
Everything::sendSmartString(getName() + " " + String(m_nSensorValue));
}
void PS_Ultrasonic::setPin(byte &trigPin,byte &echoPin)
{
m_nDigitalTriggerPin=trigPin;
m_nDigitalEchoPin=echoPin;
pinMode(m_nDigitalTriggerPin, OUTPUT); // Sets the trigPin as an Output
pinMode(m_nDigitalEchoPin, INPUT); // Sets the echoPin as an Input
}
}

View File

@@ -0,0 +1,64 @@
//******************************************************************************************
// File: PS_Ultrasonic.h
// Authors:
//
// Summary: PS_Ultrasonic is a class which implements a custom Level device capability.
// It inherits from the st::PollingSensor class.
//
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Ultrasonic sensor1(F("ultrasonic1"), 60, 0, PIN_ULTRASONIC_T, PIN_ULTRASONIC_E);
//
// st::PS_Ultrasonic() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte digitalTriggerPin - REQUIRED - the Arduino Pin to be used as a digital output to trigger ultrasonic
// - byte digitalEchoPin - REQUIRED - the Arduino Pin to be used as a digital input to read the echo
//
//
// Change History:
//
// Date Who What
// ---- --- ----
//
//
//
//******************************************************************************************
#ifndef ST_PS_Ultrasonic_H
#define ST_PS_Ultrasonic_H
#include "PollingSensor.h"
namespace st
{
class PS_Ultrasonic : public PollingSensor
{
private:
byte m_nDigitalTriggerPin;
byte m_nDigitalEchoPin;
float m_nSensorValue;
public:
//constructor - called in your sketch's global variable declaration section
PS_Ultrasonic(const __FlashStringHelper *name, unsigned int interval, int offset, byte digitalTriggerPin, byte digitalEchoPin);
//destructor
virtual ~PS_Ultrasonic();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
//inline byte getPin() const {return m_nAnalogInputPin;}
inline byte getSensorValue() const {return m_nSensorValue;}
//sets
void setPin(byte &trigPin,byte &echoPin);
};
}
#endif

View File

@@ -0,0 +1,239 @@
//******************************************************************************************
// File: PS_Voltage.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Voltage is a class which implements the SmartThings "Voltage Measurement" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// voltage on an anlog input pin and then scale it to engineering units.
//
// The last four arguments of the constructor are used as arguments to an Arduino map() function which
// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Voltage sensor1(F("voltage1"), 120, 0, PIN_VOLTAGE, 0, 1023, 0.0, 5.0);
//
// st::PS_Voltage() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value
// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value
// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting)
// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting)
// - byte numSamples - OPTIONAL - defaults to 1, number of analog readings to average per scheduled reading of the analog input
// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum
//
// Filtering/Averaging
//
// Filtering the value sent to ST is performed per the following equation
//
// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue)
//
//----------------------------------------------------------------------------------------------------------------------------------------------
// st::PS_Voltage() has a second constructor which includes a 3rd order polynomial compensation algorithm.
//
// Create an instance of this class in your sketch's global variable section
// For Example: static st::PS_Voltage sensor5(F("voltage1"), 5, 1, PIN_VOLTAGE_1, -40, 140, 0, 4095, 20, 75, -0.000000025934, 0.0001049656215, 0.9032840665333, 204.642825355678);
//
// The following arguments all all REQUIRED in order to use the Compensation Algorithm.
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value
// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value
// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting)
// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting)
// - byte numSamples - REQUIRED - number of analog readings to average per scheduled reading of the analog input
// - byte filterConstant - REQUIRED - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none, 5 = maximum
// - double Coeff1 - REQUIRED - 3rd order polynomial coefficient #1
// - double Coeff2 - REQUIRED - 3rd order polynomial coefficient #2
// - double Coeff3 - REQUIRED - 3rd order polynomial coefficient #3
// - double Coeff4 - REQUIRED - 3rd order polynomial coefficient #4
//
// 3rd order Plynomial Compensation Algorithm (useful for correcting non-linear analog to digital converters)
//
// CompensatedValue = Coeff1 * rawAnalogInput^3 + Coeff2 * rawAnalogInput^2 + Coeff3 * rawAnalogInput + Coeff4
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-04-19 Dan & Daniel Original Creation
// 2017-08-18 Dan Ogorchock Modified to return floating point values instead of integer
// 2017-08-31 Dan Ogorchock Added oversampling optional argument to help reduce noisy signals
// 2017-08-31 Dan Ogorchock Added filtering optional argument to help reduce noisy signals
// 2017-09-01 Dan Ogorchock Added 3rd order polynomial nonlinear correction compensation
// 2018-06-24 Dan Ogorchock Improved documentation / comments (above)
//
//
//******************************************************************************************
#include "PS_Voltage.h"
#include "Constants.h"
#include "Everything.h"
#include <math.h>
namespace st
{
//private
float map_double(double x, double in_min, double in_max, double out_min, double out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
//public
//constructor - called in your sketch's global variable declaration section
PS_Voltage::PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, int NumSamples, byte filterConstant):
PollingSensor(name, interval, offset),
m_fSensorValue(-1.0),
SENSOR_LOW(s_l),
SENSOR_HIGH(s_h),
MAPPED_LOW(m_l),
MAPPED_HIGH(m_h),
m_nNumSamples(NumSamples),
m_bUseCompensation(false)
{
setPin(analogInputPin);
//check for upper and lower limit and adjust accordingly
if ((filterConstant <= 0) || (filterConstant >= 100))
{
m_fFilterConstant = 1.0;
}
else if (filterConstant <= 5)
{
m_fFilterConstant = 0.05;
}
else
{
m_fFilterConstant = float(filterConstant) / 100;
}
}
//constructor - called in your sketch's global variable declaration section
PS_Voltage::PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, int NumSamples, byte filterConstant, double Coeff1, double Coeff2, double Coeff3, double Coeff4) :
PollingSensor(name, interval, offset),
m_fSensorValue(-1.0),
SENSOR_LOW(s_l),
SENSOR_HIGH(s_h),
MAPPED_LOW(m_l),
MAPPED_HIGH(m_h),
m_nNumSamples(NumSamples),
m_dCoeff1(Coeff1),
m_dCoeff2(Coeff2),
m_dCoeff3(Coeff3),
m_dCoeff4(Coeff4),
m_bUseCompensation(true)
{
setPin(analogInputPin);
//check for upper and lower limit and adjust accordingly
if ((filterConstant <= 0) || (filterConstant >= 100))
{
m_fFilterConstant = 1.0;
}
else if (filterConstant <= 5)
{
m_fFilterConstant = 0.05;
}
else
{
m_fFilterConstant = float(filterConstant) / 100;
}
}
//destructor
PS_Voltage::~PS_Voltage()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_Voltage::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_Voltage::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_Voltage::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_Voltage::getData()
{
int i;
double tempValue = 0;
long tempAnalogInput = 0;
//implement oversampling / averaging
for (i = 0; i < m_nNumSamples; i++) {
tempAnalogInput = analogRead(m_nAnalogInputPin);
if (m_bUseCompensation) {
//Serial.print(F("PS_Voltage::tempAnalogInput = "));
//Serial.print(tempAnalogInput);
tempAnalogInput = (m_dCoeff1 * pow(tempAnalogInput, 3)) + (m_dCoeff2 * pow(tempAnalogInput, 2)) + (m_dCoeff3 * tempAnalogInput) + m_dCoeff4;
//Serial.print(F(", PS_Voltage::tempAnalogInput (Compensated) = "));
//Serial.print(tempAnalogInput);
//Serial.println();
}
tempValue += map_double(tempAnalogInput, SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH);
//if (st::PollingSensor::debug)
//{
// Serial.print(F("PS_Voltage::tempValue = "));
// Serial.print(tempValue);
// Serial.println();
//}
}
tempValue = tempValue / m_nNumSamples; //calculate the average value over the number of samples
//implement filtering
if (m_fSensorValue == -1.0)
{
//first time through, no filtering
m_fSensorValue = tempValue;
}
else
{
m_fSensorValue = (m_fFilterConstant * tempValue) + (1 - m_fFilterConstant) * m_fSensorValue;
}
Everything::sendSmartString(getName() + " " + String(m_fSensorValue));
}
void PS_Voltage::setPin(byte pin)
{
m_nAnalogInputPin=pin;
}
}

View File

@@ -0,0 +1,120 @@
//******************************************************************************************
// File: PS_Voltage.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Voltage is a class which implements the SmartThings "Voltage Measurement" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// voltage on an anlog input pin and then scale it to engineering units.
//
// The last four arguments of the constructor are used as arguments to an Arduino map() function which
// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Voltage sensor1(F("voltage1"), 120, 0, PIN_VOLTAGE, 0, 1023, 0.0, 5.0);
//
// st::PS_Voltage() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value
// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value
// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting)
// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting)
// - byte numSamples - OPTIONAL - defaults to 1, number of analog readings to average per scheduled reading of the analog input
// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum
//
// Filtering/Averaging
//
// Filtering the value sent to ST is performed per the following equation
//
// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue)
//
//----------------------------------------------------------------------------------------------------------------------------------------------
// st::PS_Voltage() has a second constructor which includes a 3rd order polynomial compensation algorithm.
//
// Create an instance of this class in your sketch's global variable section
// For Example: static st::PS_Voltage sensor5(F("voltage1"), 5, 1, PIN_VOLTAGE_1, -40, 140, 0, 4095, 20, 75, -0.000000025934, 0.0001049656215, 0.9032840665333, 204.642825355678);
//
// The following arguments all all REQUIRED in order to use the Compensation Algorithm.
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value
// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value
// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting)
// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting)
// - byte numSamples - REQUIRED - number of analog readings to average per scheduled reading of the analog input
// - byte filterConstant - REQUIRED - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none, 5 = maximum
// - double Coeff1 - REQUIRED - 3rd order polynomial coefficient #1
// - double Coeff2 - REQUIRED - 3rd order polynomial coefficient #2
// - double Coeff3 - REQUIRED - 3rd order polynomial coefficient #3
// - double Coeff4 - REQUIRED - 3rd order polynomial coefficient #4
//
// 3rd order Plynomial Compensation Algorithm (useful for correcting non-linear analog to digital converters)
//
// CompensatedValue = Coeff1 * rawAnalogInput^3 + Coeff2 * rawAnalogInput^2 + Coeff3 * rawAnalogInput + Coeff4
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-04-19 Dan & Daniel Original Creation
// 2017-08-18 Dan Ogorchock Modified to return floating point values instead of integer
// 2017-08-31 Dan Ogorchock Added oversampling optional argument to help reduce noisy signals
// 2017-08-31 Dan Ogorchock Added filtering optional argument to help reduce noisy signals
// 2017-09-01 Dan Ogorchock Added 3rd order polynomial nonlinear correction compensation
// 2018-06-24 Dan Ogorchock Improved documentation / comments (above)
//
//
//******************************************************************************************
#ifndef ST_PS_VOLTAGE_H
#define ST_PS_VOLTAGE_H
#include "PollingSensor.h"
namespace st
{
class PS_Voltage: public PollingSensor
{
private:
byte m_nAnalogInputPin;
float m_fSensorValue;
double SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH;
int m_nNumSamples;
float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00
double m_dCoeff1, m_dCoeff2, m_dCoeff3, m_dCoeff4; //3rd order polynomial nonlinear correction compensation coefficients
bool m_bUseCompensation;
public:
//constructor - called in your sketch's global variable declaration section
PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l=0, double s_h=1023, double m_l=0, double m_h=5000, int NumSamples=1, byte filterConstant = 100);
//constructor with 3rd order polynomial nonlinear correction compensation coefficients - called in your sketch's global variable declaration section
PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, int NumSamples, byte filterConstant, double Coeff1, double Coeff2, double Coeff3, double Coeff4);
//destructor
virtual ~PS_Voltage();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nAnalogInputPin;}
inline float getSensorValue() const {return m_fSensorValue;}
//sets
void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,115 @@
//******************************************************************************************
// File: PS_Water.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Water is a class which implements both the SmartThings "Water Sensor" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// presence of water using an inexpensive water sensor.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Water sensor3(F("water1"), 60, 6, PIN_WATER, 200, false);
//
// st::PS_Water() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - int limit - OPTIONAL - the alarm limit to compare analog pin's reading to, above which the sensor reports "wet" instead of "dry", default = 100
// - bool invertLogic - OPTIONAL - if set to true, will invert the comparison against target from < to >, default = false
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-08-23 Dan Added optional alarm limit to constructor
// 2018-10-17 Dan Added invertLogic parameter to constructor
//
//
//******************************************************************************************
#include "PS_Water.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
//public
//constructor - called in your sketch's global variable declaration section
PS_Water::PS_Water(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int limit, bool invertLogic):
PollingSensor(name, interval, offset),
m_nSensorValue(0),
m_nSensorLimit(limit),
m_binvertLogic(invertLogic)
{
setPin(analogInputPin);
}
//destructor
PS_Water::~PS_Water()
{
}
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
void PS_Water::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (s.toInt() != 0) {
st::PollingSensor::setInterval(s.toInt() * 1000);
if (st::PollingSensor::debug) {
Serial.print(F("PS_Water::beSmart set polling interval to "));
Serial.println(s.toInt());
}
}
else {
if (st::PollingSensor::debug)
{
Serial.print(F("PS_Water::beSmart cannot convert "));
Serial.print(s);
Serial.println(F(" to an Integer."));
}
}
}
//function to get data from sensor and queue results for transfer to ST Cloud
void PS_Water::getData()
{
int m_nSensorValue = analogRead(m_nAnalogInputPin);
if (st::PollingSensor::debug)
{
Serial.print(F("PS_Water::Analog Pin value is "));
Serial.print(m_nSensorValue);
Serial.print(F(" vs limit of "));
Serial.println(m_nSensorLimit);
}
//compare the sensor's value is against the limit to determine whether to send "dry" versus "wet".
if (m_binvertLogic)
{
Everything::sendSmartString(getName() + (m_nSensorValue > m_nSensorLimit ? F(" dry") : F(" wet")));
}
else
{
Everything::sendSmartString(getName() + (m_nSensorValue < m_nSensorLimit ? F(" dry") : F(" wet")));
}
}
void PS_Water::setPin(byte pin)
{
m_nAnalogInputPin=pin;
}
}

View File

@@ -0,0 +1,77 @@
//******************************************************************************************
// File: PS_Water.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_Water is a class which implements both the SmartThings "Water Sensor" device capability.
// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the
// presence of water using an inexpensive water sensor.
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_Water sensor3(F("water1"), 60, 6, PIN_WATER, 200, false);
//
// st::PS_Water() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input
// - int limit - OPTIONAL - the alarm limit to compare analog pin's reading to, above which the sensor reports "wet" instead of "dry", default = 100
// - bool invertLogic - OPTIONAL - if set to true, will invert the comparison against target from < to >, default = false
//
// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference
// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to
// the ST Shield. For PollingSensors, this data is handled in the beSMart() function.
//
// TODO: Determine a method to persist the ST Cloud's Polling Interval data
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2015-08-23 Dan Added optional alarm limit to constructor
// 2018-10-17 Dan Added invertLogic parameter to constructor
//
//
//******************************************************************************************
#ifndef ST_PS_WATER_H
#define ST_PS_WATER_H
#include "PollingSensor.h"
namespace st
{
class PS_Water: public PollingSensor
{
private:
byte m_nAnalogInputPin; //analog pin connected to the water sensor
int m_nSensorValue; //current sensor value
int m_nSensorLimit; //alarm limit
bool m_binvertLogic; //if false use <, if true use > for comparison of AI value versus limit
public:
//constructor - called in your sketch's global variable declaration section
PS_Water(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int limit = 100, bool invertLogic = false);
//destructor
virtual ~PS_Water();
//SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly)
virtual void beSmart(const String &str);
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
inline byte getPin() const {return m_nAnalogInputPin;}
inline byte getSensorValue() const {return m_nSensorValue;}
//sets
void setPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,113 @@
//******************************************************************************************
// File: PollingSensor.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::PollingSensor is a generic class which inherits from st::Sensor. This is the
// parent class for the st::PS_Illuminace, st::PS_Water, and PS_TemperatureHumidity classes.
//
// In general, this file should not need to be modified.
//
// st::PollingSensor() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
//
//
//******************************************************************************************
#include "PollingSensor.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
bool PollingSensor::checkInterval()
{
//check for time overflow
if(millis()<m_nPreviousTime)
{
if (debug)
{
Serial.println(F("PollingSensor: millis() Overflow handled"));
}
m_nPreviousTime = 0;
}
if(m_nPreviousTime==0) //eliminates problem of there being a delay before first update() call
{
m_nPreviousTime=millis();
}
//calculate new delta time
m_nDeltaTime+=(millis()-m_nPreviousTime)-m_nOffset;
m_nOffset=0;
m_nPreviousTime=millis();
//determine interval has passed
if(m_nDeltaTime>=m_nInterval)
{
m_nDeltaTime=0;
return true;
}
else
{
return false;
}
}
//public
//constructor
PollingSensor::PollingSensor(const __FlashStringHelper *name, long interval, long offset):
Sensor(name),
m_nPreviousTime(0),
m_nDeltaTime(0),
m_nInterval(interval*1000),
m_nOffset(offset*1000)
{
}
//destructor
PollingSensor::~PollingSensor()
{
}
void PollingSensor::init()
{
getData();
}
void PollingSensor::refresh()
{
getData();
}
void PollingSensor::update()
{
if(checkInterval())
{
getData();
}
}
void PollingSensor::getData()
{
if(debug)
{
Everything::sendSmartString(getName() + F(" triggered"));
}
}
//debug flag to determine if debug print statements are executed (set value in your sketch)
bool PollingSensor::debug=false;
}

View File

@@ -0,0 +1,74 @@
//******************************************************************************************
// File: PollingSensor.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::PollingSensor is a generic class which inherits from st::Sensor. This is the
// parent class for the st::PS_Illuminace, st::PS_Water, and PS_TemperatureHumidity classes.
//
// In general, this file should not need to be modified.
//
// st::PollingSensor() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - long interval - REQUIRED - the polling interval in seconds
// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
//
//
//******************************************************************************************
#ifndef ST_POLLINGSENSOR_H
#define ST_POLLINGSENSOR_H
#include "Sensor.h"
namespace st
{
class PollingSensor: public Sensor
{
private:
unsigned long m_nPreviousTime; //in milliseconds - time of last poll
long m_nDeltaTime; //in milliseconds - elapsed time since last poll
long m_nInterval; //in milliseconds - polling interval for the sensor
long m_nOffset; //in milliseconds - offset to prevent all Polling sensors from running at the same time
virtual bool checkInterval(); //returns true and resets m_nDeltaTime if m_nInterval has been reached
public:
//constructor
PollingSensor(const __FlashStringHelper *name, long interval, long offset=0);
//destructor
virtual ~PollingSensor();
//initialization function
virtual void init();
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of each Device subclass object
virtual void refresh();
//update function
virtual void update();
//function to get data from sensor and queue results for transfer to ST Cloud
virtual void getData();
//gets
virtual void offset(long os) {m_nOffset=os;} //offset the delta time from its current value
//sets
virtual void setInterval(long interval) {m_nInterval=interval;}
//debug flag to determine if debug print statements are executed (set value in your sketch)
static bool debug;
};
}
#endif

View File

@@ -0,0 +1,206 @@
//******************************************************************************************
// File: S_TimedRelay.cpp
// Authors: Dan G Ogorchock
//
// Summary: S_TimedRelay is a class which implements the SmartThings "Relay" device capability. It features
// an automatic-turn-off time delay for a relay to emulate a button press.
//
// It inherits from the st::Sensor class and clones much from the st::Executor Class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::S_TimedRelay sensor1(F("relaySwitch1"), PIN_RELAY, LOW, true, 1000, 0, 1, 0);
//
// st::S_TimedRelay() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Ouput should use inverted logic
// - long onTime - REQUIRED - the number of milliseconds to keep the output on, DEFAULTS to 1000 milliseconds
// - long offTime - OPTIONAL - the number of milliseconds to keep the output off, DEFAULTS to 0
// - int numCycles - OPTIONAL - the number of times to repeat the on/off cycle, DEFAULTS to 1
// - byte finalState - OPTIONAL - leave in X state after finishing sequence 0 = off, 1 = on , Defaults to 0
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-12-29 Dan Ogorchock Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2019-06-23 Brian Wilson Added finalState option
// 2020-10-20 Dan Ogorchock Fixed minor bug to ensure proper reporting of device state
//
//
//******************************************************************************************
#include "S_TimedRelay.h"
#include "Constants.h"
#include "Everything.h"
namespace st
{
//private
void S_TimedRelay::writeStateToPin()
{
digitalWrite(m_nOutputPin, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState);
}
//public
//constructor
S_TimedRelay::S_TimedRelay(const __FlashStringHelper *name, byte pinOutput, bool startingState, bool invertLogic, unsigned long onTime, unsigned long offTime, unsigned int numCycles, byte finalState) :
Sensor(name),
m_bCurrentState(startingState),
m_bInvertLogic(invertLogic),
m_lOnTime(onTime),
m_lOffTime(offTime),
m_iNumCycles(numCycles),
m_iCurrentCount(numCycles),
m_nfinalState(finalState),
m_lTimeChanged(0),
m_bTimerPending(false)
{
setOutputPin(pinOutput);
if (numCycles < 1)
{
m_iNumCycles = 1;
m_iCurrentCount = 1;
Serial.println(F("S_TimedRelay:: INVALID Number of Cycles Requested! Must be at least 1. Setting to 1."));
}
}
//destructor
S_TimedRelay::~S_TimedRelay()
{
}
void S_TimedRelay::init()
{
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
}
//update function
void S_TimedRelay::update()
{
if (m_iCurrentCount < m_iNumCycles)
{
//Turn off digital output if timer has expired
if ((m_bCurrentState == HIGH) && (millis() - m_lTimeChanged >= m_lOnTime))
{
if (m_nfinalState == 1) { // final state will be on
//add one to the current count since we finished an on/off cycle, and turn on output if needed
m_iCurrentCount++;
if (m_iCurrentCount < m_iNumCycles)
{
m_bCurrentState = LOW;
writeStateToPin();
m_lTimeChanged = millis();
}
} else {
m_bCurrentState = LOW;
writeStateToPin();
m_lTimeChanged = millis();
}
}
else if ((m_bCurrentState == LOW) && (millis() - m_lTimeChanged >= m_lOffTime))
{
if (m_nfinalState == 0) { // final state will be off
//add one to the current count since we finished an on/off cycle, and turn on output if needed
m_iCurrentCount++;
if (m_iCurrentCount < m_iNumCycles)
{
m_bCurrentState = HIGH;
writeStateToPin();
m_lTimeChanged = millis();
}
} else {
m_bCurrentState = HIGH;
writeStateToPin();
m_lTimeChanged = millis();
}
}
//Check to see if we just finished the requested number of cycles
if (m_iCurrentCount == m_iNumCycles)
{
//Decrement number of active timers
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
//Queue the relay status update the ST Cloud
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
}
}
}
void S_TimedRelay::beSmart(const String &str)
{
String s = str.substring(str.indexOf(' ') + 1);
if (st::Device::debug) {
Serial.print(F("S_TimedRelay::beSmart s = "));
Serial.println(s);
}
if ((s == F("on")) && (m_bCurrentState == LOW))
{
m_bCurrentState = HIGH;
//Save time turned on
m_lTimeChanged = millis();
//Increment number of active timers
if (!m_bTimerPending)
{
st::Everything::bTimersPending++;
m_bTimerPending = true;
}
//Queue the relay status update the ST Cloud
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
//Set the initial count to zero
m_iCurrentCount = 0;
//update the digital output
writeStateToPin();
}
else if ((s == F("off")) && (m_bCurrentState == HIGH))
{
m_bCurrentState = LOW;
//Decrement number of active timers
if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--;
m_bTimerPending = false;
//Queue the relay status update the ST Cloud
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
//Reset the count to the number of required cycles to prevent Update() routine from running if someone sends an OFF command
m_iCurrentCount = m_iNumCycles;
//update the digital output
writeStateToPin();
}
else
{
//Queue the relay status update the ST Cloud
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
}
}
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
void S_TimedRelay::refresh()
{
//Queue the relay status update the ST Cloud
Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));
}
void S_TimedRelay::setOutputPin(byte pin)
{
m_nOutputPin = pin;
pinMode(m_nOutputPin, OUTPUT);
writeStateToPin();
}
}

View File

@@ -0,0 +1,90 @@
//******************************************************************************************
// File: S_TimedRelay.h
// Authors: Dan G Ogorchock
//
// Summary: S_TimedRelay is a class which implements the SmartThings "Relay" device capability. It features
// an automatic-turn-off time delay for a relay to emulate a button press.
//
// It inherits from the st::Sensor class and clones much from the st::Executor Class
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::S_TimedRelay sensor1(F("relaySwitch1"), PIN_RELAY, LOW, true, 1000, 0, 1, 0);
//
// st::S_TimedRelay() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name
// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output
// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on"
// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Ouput should use inverted logic
// - long onTime - REQUIRED - the number of milliseconds to keep the output on, DEFAULTS to 1000 milliseconds
// - long offTime - OPTIONAL - the number of milliseconds to keep the output off, DEFAULTS to 0
// - int numCycles - OPTIONAL - the number of times to repeat the on/off cycle, DEFAULTS to 1
// - byte finalState - OPTIONAL - leave in X state after finishing sequence 0 = off, 1 = on , Defaults to 0
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-12-29 Dan Ogorchock Original Creation
// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements
// 2019-06-23 Brian Wilson Added finalState option
// 2019-08-10 Dan Ogorchock Added public getStatus()
//
//
//******************************************************************************************
#ifndef ST_S_TIMEDRELAY_H
#define ST_S_TIMEDRELAY_H
#include "Sensor.h"
namespace st
{
class S_TimedRelay : public Sensor //inherits from parent Sensor Class
{
private:
//following are for the digital output
bool m_bCurrentState; //HIGH or LOW
bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic
byte m_nOutputPin; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED
unsigned long m_lOnTime; //number of milliseconds to keep digital output HIGH before automatically turning off
unsigned long m_lOffTime; //number of milliseconds to keep digital output LOW before automatically turning on
unsigned int m_iNumCycles; //number of on/off cycles of the digital output
unsigned int m_iCurrentCount; //current number of on/off cycles of the digital output
byte m_nfinalState; //desired final state of the output after the cycling has completed (typical value is 0)
unsigned long m_lTimeChanged; //time when the digital output was last changed
bool m_bTimerPending; //true if waiting on relay timer to expire
void writeStateToPin(); //function to update the Arduino Digital Output Pin
public:
//constructor - called in your sketch's global variable declaration section
S_TimedRelay(const __FlashStringHelper *name, byte pinOutput, bool startingState = LOW, bool invertLogic = false, unsigned long onTime = 1000, unsigned long offTime = 0, unsigned int numCycles = 1, byte finalState = 0);
//destructor
virtual ~S_TimedRelay();
//initialization function
virtual void init();
//update function
void update();
//SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output)
virtual void beSmart(const String &str);
//called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor
virtual void refresh();
//gets
virtual byte getPin() const { return m_nOutputPin; }
virtual bool getTimerActive() const { return m_bTimerPending; }
virtual bool getStatus() const { return m_bCurrentState; }
//sets
virtual void setOutputPin(byte pin);
};
}
#endif

View File

@@ -0,0 +1,46 @@
//******************************************************************************************
// File: Sensor.cpp
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Sensor is a generic class which inherits from st::Device. This is the
// parent class for the st::PollingSensor and st::InterruptSensor classes.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
//
//
//******************************************************************************************
#include "Sensor.h"
#include "Constants.h"
namespace st
{
//private
//public
//constructor
Sensor::Sensor(const __FlashStringHelper *name):
Device(name)
{
}
//destructor
Sensor::~Sensor()
{
}
void Sensor::beSmart(const String &str)
{
//Each derived class should implement this if they are interfacing with SmartThings over the internet.
}
}

50
lib/ST_Anything/Sensor.h Normal file
View File

@@ -0,0 +1,50 @@
//******************************************************************************************
// File: Sensor.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: st::Sensor is a generic class which inherits from st::Device. This is the
// parent class for the st::PollingSensor and st::InterruptSensor classes.
// In general, this file should not need to be modified.
//
// Change History:
//
// Date Who What
// ---- --- ----
// 2015-01-03 Dan & Daniel Original Creation
// 2019-02-09 Dan Ogorchock Moved update() from Sensor to Device
//
//
//******************************************************************************************
#ifndef ST_SENSOR_H
#define ST_SENSOR_H
#include "Device.h"
namespace st
{
//abstract
class Sensor: public Device
{
private:
public:
//constructor
Sensor(const __FlashStringHelper *name);
//destructor
virtual ~Sensor();
//SmartThings Shield data handler
virtual void beSmart(const String &str);
//all derived classes must implement these pure virtual functions
virtual void init()=0;
};
}
#endif