[DEPRECATED] ST_Anything - Arduino/ESP8266/ESP32

Yep, that’s what I figured. The Generic PS cant grab active numbers or states that are derived in the sketch. And would be to complicated to do all the sketch functions in a library and make a new library for every one. And the sketch needs these variables in the loop to make decisions for other things like when to turn on the pump, or purge, or shut off if another variable threshold is reached, so that’s not an option. So really do need a reverse callback or something.

@SawKyrom I really haven’t done much/any work with I2C.

ST_Anything is designed to be extended by anyone who would like to add additional device support. ST_Anything is written in C++ as an object oriented library. Thus, each device is treated as an object. The “Everything” class is responsible for coordinating all communications to/from SmartThings, as well as keeping all of the devices attached to the Arduino up to date.

So, in order to add additional devices, one simply needs to all a new C++ class. Depending on the type of sensor/device, you would either start with an existing “Polling Sensor”, “Interrupts Sensor”, or an “Executor”.

A Polling Sensor is a device which is read periodically (e.g. every 5 seconds, 30 seconds, etc…) This is good for reading a sensor periodically and then updating SmartThings at a reasonable rate. Used for reading analog inputs primarily, but also useful for reading any data source (like the DHT or 1-Wire temperature sensors).

An Interrupt Sensor is used to continuously monitor a GPIO digital pin for changes of state (High to Low, Low to High.) This is used for sensors like the Contact Sensor, which require near instantaneous response time. For each change of state, SmartThings is updated to make sure no transitions are missed. (Note: There is debounce logic added to prevent spurious events from being sent to ST.)

An Executor is an output only device. This type of device just waits to be told from SmartThings to change an output, or take an action of some sort. For example, this can be used to update the state of a digital output (e.g. Switch, Relay, etc…), an analog output, or even a serial or network packet.

There are a few special devices in the ST_Anything library that are a combination of some of these high-level device types (e.g. the Door Control device is a combination of an Interrupt Sensor and an Executor.)

With that high level explanation complete, let’s look at your specific requirements. I believe the easiest solution would be to simply use the existing wiring to supply power to additional NodeMCU ESP8266 microcontrollers at each key pad site. Then directly wire the sensors to those additional NodeMCU boards. Each of them will communicate via WiFi directly to the hub.

If this wouldn’t work for some reason, additional details of you project would be required to determine the best method moving forward. What are the specific sensors attached to each keypad? Are they just normal dry contact devices? How many wires are pulled from the alarm panel to each keypad?

Hope this helps to get you started. Let me know if you have any questions.

@kampto Have you considered simply using my “SmartThings” communications library to write your own sketch? It sounds like you want to add some sophisticated local Arduino control, while being able to communicate with SmartThings, correct?

Depending on your requirements, simply adding the “SmartThings” communications library to your sketch may be exactly what you need. ST_Anything uses the SmartThings communications library for its ST connectivity. However, ST_Anything is primarily designed to act as a bridge between Arduino devices and SmartThings. It does not really accommodate extensive local control, however it is possible. Can you explain exactly what you are trying to accomplish? I will try to provide an explanation of how I would proceed…

@polargeek Can you please provide a copy of your ST_Anything-based sketch for review? Also, one of your working example sketches for the relay module would be helpful as well (or a link to one?)

I’ll try to help out, but I really need for information.

Note: When copying and pasting code into this forum, in the edit window, please be sure to select/highlight all of your code, and then click the Preformatted Text button ( < / > ) in the edit window menu bar. Otherwise, the code gets messed up.

@Ryan780 @Garnet I have not made any progress on OTA updates for the ESP8266 platform. If anyone wants to take a crack at adding OTA updates to ST_Anything, I’d be happy to accept a pull request to the ST_Anything GitHub repository.

Dan, I want the controller to run all of its functions and simply just have ST monitor a few things(Voltage, current, flow, etc…) Things that are directly connected to pins (contact sensors, DS18B20, Voltage AI’s,…) I can easily publish to ST using your ST_Anything. That part is working great.

But For example in this function in the sketch, how can I send the GalTotal to ST? This number is changing constantly while running and would like to poll it every couple minutes or so and send to ST for monitoring.

void flow_calc()
{
if (digitalRead(PUMP) == HIGH) { // Only incriment flow if pump is on…
if ((millis() - oldTime) > 1000) // Only process flowrate after 1sec or more
{ // detach interupt for calc, if code runs slow the (millis()-oldTime) will factor the extra time past 1sec.
detachInterrupt(flowsensor); // Disable the interrupt while calculating flow rate and sending the value
flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor / 3.79; // 3.79 to convert to Gal
GalTotal = GalTotal +((millis() - oldTime) /1000.00 / 60.00 * flowRate); // incriment Gallons Per day
oldTime = millis(); // reset time in between interupts for
pulseCount = 0; // Reset the pulse counter so we can start incrementing again
attachInterrupt(digitalPinToInterrupt(flowsensor), pulseCounter, FALLING);
}
}
else flowRate=0; return; // Exit flow routine if pump is off
}

If you just want to send data to SmartThings from within the sketch, all you have to do is make a properly formatted call as shown below:

st::Everything::sendSmartString(“voltage1 1234”);

In this case, you don’t even need to add a voltage device within the setup() routine. It would be bad if you did, actually. If a real polling sensor is added, it will overwrite the value you send in your sketch.

When you send a properly formatted text string using the call above, The Parent Device will automatically create a child device on your behalf. You could just as easily send “temperature1 1234” and a child temperature device would be created. Just do NOT use the same name as any of your actual ST_Anything devices declared in your setup() routine. You could use “generic1 1234” as well, however there is no SmartThings Capability named generic. Therefore, any “generic” devices you create in SmartThings are really only useful for display purposes in the ST App on your phone. Of course, could also write your own SmartApp to utilize this data. Fitting it into one of the existing SmartThings Capabilities is usually the best way to go though.

Please see the naming convention shown in the ReadMe as shown below.

The names of the devices you create in the Arduino setup() routine MUST MATCH EXACTLY the names the Parent Device Handler code expects. The names are CaSe SenSiTiVe! Do not get creative with naming in the Arduino sketch as the Child Devices will not be created. Follow the naming convention as seen in the "ST_Anything_Multiples_xxxx.ino" sketches
Contact Sensors: "contact1", "contact2", "contact3", ...
Alarm: "alarm1", "alarm2", "alarm3", ...
Motion: "motion1", "motion2", "motion3", ...
Smoke Detectors: "smoke1", "smoke2", "smoke3", ...
Switch: "switch1", "switch2", "switch3", ...
Dimmer Switch: "dimmerSwitch1", "dimmerSwitch2", "dimmerSwitch3", ...
Door Control: "doorControl1", "doorControl2", "doorControl3", ...
Water Sensor: "water1", "water2", "water3", ...
CO Detector: "carbonMonoxide1", "carbonMonoxide2", "carbonMonoxide3", ...
Button: "button1", "button2", "button3"
Illuminance: "illuminance1", "illuminance2", "illuminance3", ...
Voltage: "voltage1", "voltage2", "voltage3", ...
RelaySwitch: "relaySwitch1", "relaySwitch2", "relaySwitch3", ...
Temperature: "temperature1", "temperature2", "temperature3", ...
Humidity: "humidity1", "humidity2", "humidity3", ...

Here’s a link to the ST Capabilities Reference Document for your info.

http://docs.smartthings.com/en/latest/capabilities-reference.html

Thanks, Just tried that. Put this into the loop:
st::Everything::sendSmartString(“voltage2 1234”);

And get these compile errors:
error: no matching function for call to ‘st::Everything::sendSmartString(const char [14])’

C:\Users…/Everything.h:77:16: note: static bool st::Everything::sendSmartString(String&)
static bool sendSmartString(String &str); //sendSmartString() may edit the string reference passed to it - queues messages - preferable

Hey, firstly Dan & Dan - just wow, this is such a great project, just reading the thread it’s obvious this has helped so many people… huge thanks.

I’m a relative noob to all things arduino, so much of what I have done to date is copy and paste with a bit of interpretation here and there.

I’ve managed to sniff and repeat my wireless boiler thermostats on and off signal and can control my boiler using smartthings via your awesome code.

However:

  • I’ve edited the EX_Switch.cpp file, is this safe or will future updates break my customisations?
  • I need to find a way of repeating the on/off signal every 3 minutes, otherwise the boiler turns off. I presume this is some sort of inbuilt safety feature in case the batteries in the standard thermostat fail. How do I determine what state the switch is in and then using this send a repeat signal every 3 minutes?

Any help much appreciated!

@ogiewon ,
Thanks for looking. My ST_Anything sketch is the multiples sketch with things I don’t have commented out.

//******************************************************************************************
//  File: ST_Anything_Multiples_ESP8266WiFi.ino
//  Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
//  Summary:  This Arduino Sketch, along with the ST_Anything library and the revised SmartThings 
//            library, demonstrates the ability of one NodeMCU ESP8266 to 
//            implement a multi input/output custom device for integration into SmartThings.
//            The ST_Anything library takes care of all of the work to schedule device updates
//            as well as all communications with the NodeMCU ESP8266's WiFi.
//
//            ST_Anything_Multiples implements the following ST Capabilities as a demo of what is possible with a single NodeMCU ESP8266
//              - 1 x Alarm device (using a simple digital output)
//              - 1 x Contact Sensor devices (used to monitor magnetic door sensors)
//              - 1 x Switch devices (used to turn on a digital output (e.g. LED, relay, etc...)
//              - 1 x Motion devices (used to detect motion)
//              - 1 x Smoke Detector devices (using simple digital input)
//              - 1 x Temperature Measurement devices (Temperature from Dallas Semi 1-Wire DS18B20 device)
//              - 1 x Relay Switch devices (used to turn on a digital output for a set number of cycles And On/Off times (e.g.relay, etc...))
//              - 2 x Button devices (sends "pushed" if held for less than 1 second, else sends "held"
//              - 1 x Water Sensor devices (using the 1 analog input pin to measure voltage from a water detector board)
//    
//  Change History:
//
//    Date        Who            What
//    ----        ---            ----
//    2015-01-03  Dan & Daniel   Original Creation
//    2017-02-12  Dan Ogorchock  Revised to use the new SMartThings v2.0 library
//    2017-04-17  Dan Ogorchock  New example showing use of Multiple device of same ST Capability
//                               used with new Parent/Child Device Handlers (i.e. Composite DH)
//    2017-05-25  Dan Ogorchock  Revised example sketch, taking into account limitations of NodeMCU GPIO pins
//
//******************************************************************************************
//******************************************************************************************
// SmartThings Library for ESP8266WiFi
//******************************************************************************************
#include <SmartThingsESP8266WiFi.h>

//******************************************************************************************
// ST_Anything Library 
//******************************************************************************************
#include <Constants.h>       //Constants.h is designed to be modified by the end user to adjust behavior of the ST_Anything library
#include <Device.h>          //Generic Device Class, inherited by Sensor and Executor classes
#include <Sensor.h>          //Generic Sensor Class, typically provides data to ST Cloud (e.g. Temperature, Motion, etc...)
#include <Executor.h>        //Generic Executor Class, typically receives data from ST Cloud (e.g. Switch)
#include <InterruptSensor.h> //Generic Interrupt "Sensor" Class, waits for change of state on digital input 
#include <PollingSensor.h>   //Generic Polling "Sensor" Class, polls Arduino pins periodically
#include <Everything.h>      //Master Brain of ST_Anything library that ties everything together and performs ST Shield communications

#include <PS_Illuminance.h>  //Implements a Polling Sensor (PS) to measure light levels via a photo resistor

#include <PS_TemperatureHumidity.h>  //Implements a Polling Sensor (PS) to measure Temperature and Humidity via DHT library
#include <PS_DS18B20_Temperature.h>  //Implements a Polling Sesnor (PS) to measure Temperature via DS18B20 libraries 
#include <PS_Water.h>        //Implements a Polling Sensor (PS) to measure presence of water (i.e. leak detector)
#include <IS_Motion.h>       //Implements an Interrupt Sensor (IS) to detect motion via a PIR sensor
#include <IS_Contact.h>      //Implements an Interrupt Sensor (IS) to monitor the status of a digital input pin
#include <IS_Smoke.h>        //Implements an Interrupt Sensor (IS) to monitor the status of a digital input pin
#include <IS_DoorControl.h>  //Implements an Interrupt Sensor (IS) and Executor to monitor the status of a digital input pin and control a digital output pin
#include <IS_Button.h>       //Implements an Interrupt Sensor (IS) to monitor the status of a digital input pin for button presses
#include <EX_Switch.h>       //Implements an Executor (EX) via a digital output to a relay
#include <EX_Alarm.h>        //Implements Executor (EX)as an Alarm Siren capability via a digital output to a relay
#include <S_TimedRelay.h>    //Implements a Sensor to control a digital output pin with timing capabilities

//*************************************************************************************************
//NodeMCU v1.0 ESP8266-12e Pin Definitions (makes it much easier as these match the board markings)
//*************************************************************************************************
//#define LED_BUILTIN 16
//#define BUILTIN_LED 16
//
//#define D0 16  //no internal pullup resistor
//#define D1  5
#define D2  4
//#define D3  0  //must not be pulled low during power on/reset, toggles value during boot
//#define D4  2  //must not be pulled low during power on/reset, toggles value during boot
//#define D5 14
//#define D6 12
//#define D7 13
//#define D8 15  //must not be pulled high during power on/reset

//******************************************************************************************
//Define which Arduino Pins will be used for each device
//******************************************************************************************
//#define PIN_WATER_1               A0  //NodeMCU ESP8266 only has one Analog Input Pin 'A0'

//#define PIN_ALARM_1               D0  //SmartThings Capabilty "Alarm"
#define PIN_SWITCH_1              D2  //SmartThings Capability "Switch"
//#define PIN_CONTACT_1             D2  //SmartThings Capabilty "Contact Sensor"
//#define PIN_BUTTON_1              D3  //SmartThings Capabilty Button / Holdable Button (Normally Open!)
//#define PIN_BUTTON_2              D4  //SmartThings Capabilty Button / Holdable Button (Normally Open!)
//#define PIN_MOTION_1              D5  //SmartThings Capabilty "Motion Sensor" (HC-SR501 PIR Sensor)
//#define PIN_SMOKE_1               D6  //SmartThings Capabilty "Smoke Detector"
//#define PIN_TEMPERATURE_1         D7  //SmartThings Capabilty "Temperature Measurement" (Dallas Semiconductor DS18B20)
//#define PIN_TIMEDRELAY_1          D8  //SmartThings Capability "Relay Switch"

//******************************************************************************************
//ESP8266 WiFi Information
//******************************************************************************************
String str_ssid     = "RaggedAss";                           //  <---You must edit this line!
String str_password = "Password";                   //  <---You must edit this line!
IPAddress ip(172, 16, 33, 151);       //Device IP Address       //  <---You must edit this line!
IPAddress gateway(172, 16, 33, 253);    //Router gateway          //  <---You must edit this line!
IPAddress subnet(255, 255, 255, 0);   //LAN subnet mask         //  <---You must edit this line!
IPAddress dnsserver(172, 16, 33, 4);  //DNS server              //  <---You must edit this line!
const unsigned int serverPort = 8090; // port to run the http server on

// Smartthings Hub Information
IPAddress hubIp(172, 16, 33, 65);    // smartthings hub ip     //  <---You must edit this line!
const unsigned int hubPort = 39500;   // smartthings hub port

//******************************************************************************************
//st::Everything::callOnMsgSend() optional callback routine.  This is a sniffer to monitor 
//    data being sent to ST.  This allows a user to act on data changes locally within the 
//    Arduino sktech.
//******************************************************************************************
void callback(const String &msg)
{
//  Serial.print(F("ST_Anything Callback: Sniffed data = "));
//  Serial.println(msg);
  
  //TODO:  Add local logic here to take action when a device's value/state is changed
  
  //Masquerade as the ThingShield to send data to the Arduino, as if from the ST Cloud (uncomment and edit following line)
  //st::receiveSmartString("Put your command here!");  //use same strings that the Device Handler would send
}

//******************************************************************************************
//Arduino Setup() routine
//******************************************************************************************
void setup()
{
  //******************************************************************************************
  //Declare each Device that is attached to the Arduino
  //  Notes: - For each device, there is typically a corresponding "tile" defined in your 
  //           SmartThings Device Hanlder Groovy code, except when using new COMPOSITE Device Handler
  //         - For details on each device's constructor arguments below, please refer to the 
  //           corresponding header (.h) and program (.cpp) files.
  //         - The name assigned to each device (1st argument below) must match the Groovy
  //           Device Handler names.  (Note: "temphumid" below is the exception to this rule
  //           as the DHT sensors produce both "temperature" and "humidity".  Data from that
  //           particular sensor is sent to the ST Hub in two separate updates, one for 
  //           "temperature" and one for "humidity")
  //         - The new Composite Device Handler is comprised of a Parent DH and various Child
  //           DH's.  The names used below MUST not be changed for the Automatic Creation of
  //           child devices to work properly.  Simply increment the number by +1 for each duplicate
  //           device (e.g. contact1, contact2, contact3, etc...)  You can rename the Child Devices
  //           to match your specific use case in the ST Phone Application.
  //******************************************************************************************
  //Polling Sensors
//  static st::PS_Water               sensor1(F("water1"), 60, 20, PIN_WATER_1, 200);
//  static st::PS_DS18B20_Temperature sensor2(F("temperature1"), 15, 0, PIN_TEMPERATURE_1, false, 10, 1); 
  
  //Interrupt Sensors 
//  static st::IS_Contact             sensor3(F("contact1"), PIN_CONTACT_1, LOW, true);
//  static st::IS_Button              sensor4(F("button1"), PIN_BUTTON_1, 1000, LOW, true, 500);
//  static st::IS_Button              sensor5(F("button2"), PIN_BUTTON_2, 1000, LOW, true, 500);
//  static st::IS_Motion              sensor6(F("motion1"), PIN_MOTION_1, HIGH, false);
//  static st::IS_Smoke               sensor7(F("smoke1"), PIN_SMOKE_1, HIGH, true, 500);

  //Special sensors/executors (uses portions of both polling and executor classes)
//  static st::S_TimedRelay           sensor8(F("relaySwitch1"), PIN_TIMEDRELAY_1, LOW, false, 3000, 0, 1);
  
  //Executors
//  static st::EX_Alarm executor1(F("alarm1"), PIN_ALARM_1, LOW, true);
  static st::EX_Switch executor2(F("switch1"), PIN_SWITCH_1, LOW, false);  //Inverted logic for "Active Low" Relay Board
  
  //*****************************************************************************
  //  Configure debug print output from each main class 
  //  -Note: Set these to "false" if using Hardware Serial on pins 0 & 1
  //         to prevent communication conflicts with the ST Shield communications
  //*****************************************************************************
  st::Everything::debug=true;
  st::Executor::debug=true;
  st::Device::debug=true;
  st::PollingSensor::debug=true;
  st::InterruptSensor::debug=true;

  //*****************************************************************************
  //Initialize the "Everything" Class
  //*****************************************************************************

  //Initialize the optional local callback routine (safe to comment out if not desired)
  st::Everything::callOnMsgSend = callback;
  
  //Create the SmartThings ESP8266WiFi Communications Object
    //STATIC IP Assignment - Recommended
    st::Everything::SmartThing = new st::SmartThingsESP8266WiFi(str_ssid, str_password, ip, gateway, subnet, dnsserver, serverPort, hubIp, hubPort, st::receiveSmartString);
 
    //DHCP IP Assigment - Must set your router's DHCP server to provice a static IP address for this device's MAC address
    //st::Everything::SmartThing = new st::SmartThingsESP8266WiFi(str_ssid, str_password, serverPort, hubIp, hubPort, st::receiveSmartString);

  //Run the Everything class' init() routine which establishes WiFi communications with SmartThings Hub
  st::Everything::init();
  
  //*****************************************************************************
  //Add each sensor to the "Everything" Class
  //*****************************************************************************
//  st::Everything::addSensor(&sensor1);
//  st::Everything::addSensor(&sensor2);
//  st::Everything::addSensor(&sensor3);
//  st::Everything::addSensor(&sensor4); 
//  st::Everything::addSensor(&sensor5); 
//  st::Everything::addSensor(&sensor6); 
//  st::Everything::addSensor(&sensor7);  
//  st::Everything::addSensor(&sensor8);  
      
  //*****************************************************************************
  //Add each executor to the "Everything" Class
  //*****************************************************************************
//  st::Everything::addExecutor(&executor1);
  st::Everything::addExecutor(&executor2);
    
  //*****************************************************************************
  //Initialize each of the devices which were added to the Everything Class
  //*****************************************************************************
  st::Everything::initDevices();
  
}

//******************************************************************************************
//Arduino Loop() routine
//******************************************************************************************
void loop()
{
  //*****************************************************************************
  //Execute the Everything run method which takes care of "Everything"
  //*****************************************************************************
  st::Everything::run();
}

And this is my working sketch

#include <ESP8266WiFi.h>
 
// Esp8266 pinouts
#define ESP8266_GPIO2    2  // Blue LED.
#define ESP8266_GPIO4    4  // Relay control. 
#define ESP8266_GPIO5    5  // Optocoupler input.
#define LED_PIN          ESP8266_GPIO2
// WiFi Definitions.
IPAddress ip(172, 16, 33, 151);
IPAddress gateway(172, 16, 33, 253);
IPAddress subnet(255, 255, 255, 0);
IPAddress DNS(172, 16, 33, 4);
const char ssid[] = "RaggedAss";
const char pswd[] = "password";
WiFiServer server( 80 );

volatile int relayState = 0;      // Relay state.
 
void setup() {
  initHardware();
  connectWiFi();
  server.begin();
}
 
void GetClient( WiFiClient client ) {
  // Read the first line of the request.
  String req = client.readStringUntil( '\r' );
  Serial.println( req );
  client.flush();
 
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n";
 
  if ( req.indexOf( "OPTIONS" ) != -1 ) {
    s += "Allows: GET, OPTIONS";
 
  } else if ( req.indexOf( "GET" ) != -1 ) {
    if ( req.indexOf( "open" ) != -1 ) {
      // relay on!
      s += "relay on!";
      relayState = 1;
      digitalWrite( ESP8266_GPIO4, 1 ); // Relay control pin.
     
    } else if ( req.indexOf( "close" ) != -1 ) {
      // relay off!
      s += "relay off!";
      relayState = 0;
      digitalWrite( ESP8266_GPIO4, 0 ); // Relay control pin.
     
    } else if ( req.indexOf( "toggle" ) != -1 ) {
      // relay on!
      s += "relay on!";
      relayState = 1;
      digitalWrite( ESP8266_GPIO4, 1 ); // Relay control pin.
      delay(10000);
      // relay off!
      s += "relay off!";
      relayState = 0;
      digitalWrite( ESP8266_GPIO4, 0 ); // Relay control pin.

    } else if ( req.indexOf( "relay" ) != -1 ) {
      if ( relayState == 0 )
        // relay off!
        s += "relay off!";
      else
        // relay on!
        s += "relay on!";
 
    } else if ( req.indexOf( "io" ) != -1 ) {
      if ( digitalRead( ESP8266_GPIO5 ) == 0 )
        s += "input io is:0!";
      else
        s += "input io is:1!";
     
    } else if ( req.indexOf( "MAC" ) != -1 ) {
      uint8_t mac[WL_MAC_ADDR_LENGTH];
      WiFi.softAPmacAddress( mac );
      String macID = String( mac[WL_MAC_ADDR_LENGTH - 5], HEX) + String( mac[WL_MAC_ADDR_LENGTH - 4], HEX) +
                     String( mac[WL_MAC_ADDR_LENGTH - 3], HEX) + String( mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
                     String( mac[WL_MAC_ADDR_LENGTH - 1], HEX) + String( mac[WL_MAC_ADDR_LENGTH], HEX);
      macID.toUpperCase();
      s += "MAC address: " + macID;
 
    } else
      s += "Invalid Request.<br> Try: open/close/toggle/relay/io/MAC";
 
  } else 
    s = "HTTP/1.1 501 Not Implemented\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n";
          
  client.flush();
  s += "</html>\n";
 
  // Send the response to the client.
  client.print( s );
  delay( 1 );
  Serial.println( "Client response sent." );
}
 
void loop() {
  // Check if a client has connected.
  WiFiClient client = server.available();
  if ( client ) 
    GetClient( client );
}
 
void connectWiFi() {
  byte ledStatus = LOW;
  WiFi.config(ip, gateway, subnet, DNS);
  delay(100);
  Serial.println();
  Serial.println( "Connecting to: " + String( ssid ) );
  // Set WiFi mode to station (as opposed to AP or AP_STA).
  WiFi.mode( WIFI_STA );
 
  // WiFI.begin([ssid], [passkey]) initiates a WiFI connection.
  // to the stated [ssid], using the [passkey] as a WPA, WPA2, or WEP passphrase.
  WiFi.begin( ssid, pswd );
 
  while ( WiFi.status() != WL_CONNECTED ) {
    // Blink the LED.
    digitalWrite( LED_PIN, ledStatus ); // Write LED high/low.
    ledStatus = ( ledStatus == HIGH ) ? LOW : HIGH;
    delay( 100 );
  }
 
  Serial.println( "WiFi connected" );  
  Serial.println( "IP address: " );
  Serial.println( WiFi.localIP() );
}
 
void initHardware() {
  Serial.begin( 115200 );
  pinMode( ESP8266_GPIO4, OUTPUT );       // Relay control pin.
  pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin.
  pinMode( LED_PIN, OUTPUT );             // ESP8266 module blue LED.
  digitalWrite( ESP8266_GPIO4, 0 );       // Set relay control pin low.
}

@kampto Sorry about that. Here is the corrected example code. NOTE: Please do not try sending data on every iteration of the loop() as this will overload the network, the ST Hub, and the ST Cloud!!! The code below is just an example that compiles to show you the proper syntax. Also, DO NOT put any delay() statements in the loop() function, or any other function for that matter. ST_Anything needs every iteration of the loop() to complete as quickly as possible in order for the communications with the ST hub to work correctly. This also means that you should not add any long-running looping routines inside the Arduino loop() function. Use the millis() function to determine if enough time has passed before sending successive packets to SmartThings.

void loop()
{
  //*****************************************************************************
  //Execute the Everything run method which takes care of "Everything"
  //*****************************************************************************
  st::Everything::run();
  
  String strTemp("voltage2 1234");
  st::Everything::sendSmartString(strTemp);
}

@willcm Glad to hear you’re finding ST_Anything useful for your project. As for modifying the EX_Switch.cpp file, that is not the recommended method of extending the capabilities of ST_Anything. Ideally, you would simply add a new class (i.e. a new .h and .cpp file) with new file names and internal class name. Doing this prevents any possibility of your changes being overwritten.

However, I think your better option is to use my S_TimedRelay class to take care of cycling the digital output to your boiler. Take a look at the documentation for this device class at the top of the .h or .cpp file.

Here is a configuration that will turn on the output for 3 mins, then off for 1 second, and then repeat that pattern 480 times (480 x 3 mins = 1440 mins / 60 = 24 hours.)

st::S_TimedRelay sensor1("relaySwitch1", PIN_RELAY, LOW, true, 180000, 1000, 480);

This should able to accomplish your boiler control goals without modifying code. Whenever SmartThings turns ‘on’ this device, it will begin its cycling routine. It will stop cycling either when ST issues an ‘off’ command, or after 480 cycles. You may want to lower the ‘480’ to a more reasonable/safe value.

//******************************************************************************************
//  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("relaySwitch1", PIN_RELAY, LOW, true, 1000, 0, 1);
//
//			  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, DEFGAULTS to 1000 milliseconds
//				- long offTime - OPTIONAL - the number of milliseconds to keep the output off, DEFAULTS to 0
//				- intnumCycles - OPTIONAL - the number of times to repeat the on/off cycle, DEFAULTS to 1
//

Hi Dan,

thanks for this, yes that looks closer to what I need - it’s a combination of the two classes I think, not sure if that’s possible?

The reason is that I need to send 3 pulses of the following high and low states with a delay of 1 second between each

This is the boiler on command, the off command is similar i.e. 3 pulses of various high and low states with 1 second delay between each.

            digitalWrite(outPin,LOW);  delayMicroseconds(0);
			digitalWrite(outPin,HIGH);  delayMicroseconds(607);
			digitalWrite(outPin,LOW); delayMicroseconds(300);
			digitalWrite(outPin,HIGH);  delayMicroseconds(700);
			digitalWrite(outPin,LOW); delayMicroseconds(333);
			digitalWrite(outPin,HIGH);  delayMicroseconds(667);
			digitalWrite(outPin,LOW); delayMicroseconds(400);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(400);
			digitalWrite(outPin,HIGH);  delayMicroseconds(633);
			digitalWrite(outPin,LOW); delayMicroseconds(400);
			digitalWrite(outPin,HIGH);  delayMicroseconds(633);
			digitalWrite(outPin,LOW); delayMicroseconds(400);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1167);
			digitalWrite(outPin,LOW); delayMicroseconds(900);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(900);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1133);
			digitalWrite(outPin,LOW); delayMicroseconds(867);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1100);
			digitalWrite(outPin,LOW); delayMicroseconds(900);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1100);
			digitalWrite(outPin,LOW); delayMicroseconds(400);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(433);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(967);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1100);
			digitalWrite(outPin,LOW); delayMicroseconds(400);
			digitalWrite(outPin,HIGH);  delayMicroseconds(633);
			digitalWrite(outPin,LOW); delayMicroseconds(900);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(433);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(433);
			digitalWrite(outPin,HIGH);  delayMicroseconds(633);
			digitalWrite(outPin,LOW); delayMicroseconds(400);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1100);
			digitalWrite(outPin,LOW); delayMicroseconds(1000);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(500);
			digitalWrite(outPin,HIGH);  delayMicroseconds(633);
			digitalWrite(outPin,LOW); delayMicroseconds(467);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(467);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(500);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1067);
			digitalWrite(outPin,LOW); delayMicroseconds(500);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(500);
			digitalWrite(outPin,HIGH);  delayMicroseconds(600);
			digitalWrite(outPin,LOW); delayMicroseconds(967);
			digitalWrite(outPin,HIGH);  delayMicroseconds(1100);
			digitalWrite(outPin,LOW); delayMicroseconds(500);
			digitalWrite(outPin,HIGH);  delayMicroseconds(567);
			digitalWrite(outPin,LOW);

Based om that additional information… I believe your current implementation (modifying the standard EX_Switch class) is probably the best method to accomplish your goals.

It almost looks like you’re trying to emulate serial communications between the microcontroller and the boiler control system. If it is simply serial communications, have you considered simply using Serial.print() commands to talk to the boiler control system? It might make the system more robust in the long run.

Thanks @ogiewon I’m essentially trying to emulate an RF signal that that my wireless thermostat sends to my boiler to either turn it on or off.

I’ll carry on creating a class based on the EX_Switch class and will take a look at Serial.print() - all new to me, much to learn!

Thanks again :wink:

1 Like

Ha!!! It works, thanks so much…

Here’s my function at a set interval and putting flow rate floats into the string.
void st_pollSketch()
{
if (millis() - st_pollTimer > st_pollInterval) {

char result[8]; // Size plus end null
dtostrf(flowRate, 4, 1, result); // float variable, 4 is min width, 1 is # of dec., result to buffer
String strResult(result);
String strTemp("voltage2 " + strResult);
st::Everything::sendSmartString(strTemp);

st_pollTimer = millis(); // reset poll counter
}
else return;
}

1 Like

Excellent! Glad to hear it is working for your application.

Hey @ogiewon, sorry to bother you I’m struggling to get the delay implemented…

So I’ve created a hacky sketch based on your ST_Anything_Relays_Buttons_ESP8266 board

In a nutshell there are 2 pins set, D1. is the switch status and D2. is the RF pin set to send the RF code.

If I set without any delay the the status of the switch in smartthings is correct BUT my RF code i.e. pin2 is outputted constantly

//******************************************************************************************
//Arduino Loop() routine
//******************************************************************************************
void loop()
{
  //*****************************************************************************
  //Execute the Everything run method which takes care of "Everything"
  //*****************************************************************************
  st::Everything::run();

  nCurrentVal = digitalRead(D1);
    
  if(nCurrentVal == 1)
  {
      Serial.print(F("RF Loop code sending On Signal"));
      rfOn();  // Send Boiler On RF code
  }
  
  if(nCurrentVal == 0)
  {
      Serial.print(F("RF Loop code sending Off Signal"));
      rfOff();  // Send Boiler Off Code
  }

}

If I add a delay as below, my RF code is correctly delayed and run every 3 minutes BUT the status of the switch is not correct in smartthings, presumably because the code is still stuck in the delay function and so cannot send the status of the switch to smartthings.

//******************************************************************************************
//Arduino Loop() routine
//******************************************************************************************
void loop()
{
  //*****************************************************************************
  //Execute the Everything run method which takes care of "Everything"
  //*****************************************************************************
  st::Everything::run();

  nCurrentVal = digitalRead(D1);

  unsigned long offTime = 3 * 60 * 1000; // 3 minutes.
    
  if(nCurrentVal == 1)
  {
      Serial.print(F("RF Loop code sending On Signal"));
      rfOn();  // Send Boiler On RF code
      delay(offTime);
  }
  
  if(nCurrentVal == 0)
  {
      Serial.print(F("RF Loop code sending Off Signal"));
      rfOff();  // Send Boiler Off Code
      delay(offTime);
  }

}

Being a noob to all this, I can’t get my head around how I can delay the RF code but still allow smartthings to instantly update the status of the switch…

What I can interpret is that the delay code would be better in the same library that is determining the status of the switch - that way everything would be tied together but I have the same issue there i.e.

  • I can delay the RF code send but the status of the switch isn’t relayed to smartthings cloud
    OR
  • I can relay the status of the switch accurately to smartthing cloud but I can’t delay the RF code send

I’ve looked at the S_TimedRelay code as I believe some of the answer is in there but I have to admit I’m more of a python guy (for my sins!) and I just can’t interpret the code so well.

I’d really appreciate some help and guidance

Thanks!

@willcm You definitely do not want to ever add any “delay()” statements to ST_Anything (either in your sketch or in any of the ST_Anything code.) The ST_Anything and SmartThings libraries require continuous execution of the main sketch’s loop() function in order to operate correctly.

You should utilize the Arduino “millis()” function to implement code that only executes once a specified amount of time has been exceeded. Please see this article for an example of how to implement this -
https://www.arduino.cc/en/tutorial/BlinkWithoutDelay

@ogiewon thanks for that, got me going, finally got it working!

One more question - is there a way to poll smartthings cloud for the switch state instead of reading the state of the pin (though I guess they are the same thing - just might be useful for me in other projects in the future)

For anyone that it may be interested here’s my final sketch loop code

  int interval = 3 * 60 * 1000; // Interval is how long we wait (3 minutes)
  unsigned long previousMillis = 0; // Tracks the time since last event fired
  int lastSwitchState = 0; // switch is initially set low
  int switchState = 0; // switch is initially set low

//******************************************************************************************
//Arduino Loop() routine
//******************************************************************************************
void loop()
{
  //*****************************************************************************
  //Execute the Everything run method which takes care of "Everything"
  //*****************************************************************************
  st::Everything::run();

  switchState = digitalRead(D1);

  // compare the switchState to its previous state
  // if state change
  // run RF send code regardless of whether timer has lapsed (state change)
  if (switchState != lastSwitchState)
  {
    unsigned long currentMillis = millis(); // Get snapshot of current time
    Serial.print(F("Switch change detected... running code"));
    if(switchState == 1) // if switch is on
    {
        Serial.print(F("RF Loop code sending On Signal"));
        rfOn();  // Send Boiler On RF code
    }
    
    else if (switchState == 0) // if switch is off
    {
        Serial.print(F("RF Loop code sending Off Signal"));
        rfOff();  // Send Boiler Off Code
    }
    // record the switch status
    lastSwitchState = switchState;

    // Use the snapshot to set track time until next event
    previousMillis = currentMillis;
  }

  // state is still the same check 
  else if (switchState == lastSwitchState)
  {
    unsigned long currentMillis = millis(); // Get snapshot of current time

    // How much time has passed, accounting for rollover with subtraction!
    if ((unsigned long)(currentMillis - previousMillis) >= interval) { 
      // It's time to do something!
      if(switchState == 1) // if switch is on
      {
          Serial.print(F("RF Loop code sending On Signal"));
          rfOn();  // Send Boiler On RF code
      }
      
      else if (switchState == 0) // if switch is off
      {
          Serial.print(F("RF Loop code sending Off Signal"));
          rfOff();  // Send Boiler Off Code
      }
    
      // Use the snapshot to set track time until next event
      previousMillis = currentMillis;
    }
  
    // save the current state as the last state, for next time through the loop
    lastSwitchState = switchState;
  }

}