Arduino Integration?

I received a message from my smartphone through the app, but the smartthub is not receiving anything. Or at least that I can tell. I uncommented the ‘debug’ code in the device handler. I am not getting any kind of messages in the parse function.

i have the arduino code here. The file is ‘gd_monitor’.

That helps immensely. One thing I noticed immediately is your delay at the end of the loop(). You really need to remove the delay() function as it is keeping the smartthings.run() from running. It needs to always get called continuously, not only once in a while.

You’ll need to use a non blocking method to know when it’s time to read your sensor and determine if it is time to send data to SmartThings. Also, make sure you don’t flood SmartThings with too much traffic. Only send if the value has changed, and when the ESP8266 powers up.

All of these items and issues are what led me to create the ST_Anything library. It takes care of all of the scheduling of reading sensors and sending updates to ST.

It doesn’t look like it would be too hard to add support for an “ultrasonic contact sensor” to the ST_Anything library. Let me know how you’d like to proceed. If I have some time, I’ll try to get your code working.

By the way, did you try the On/Off example sketch and corresponding device handler without modifications (except IP address settings)? Just curious as that is an easy way to troubleshoot the basics before adding in your custom logic for the ultrasonic sensor.

Peter,

Here is the fixed Arduino Sketch and a Device Handler. Both are fully tested and work as far as two-way communications is concerned. If you look at the Device Handler, you will see it implements the SmartThings “Contact Sensor” and “Switch” device capabilities.

The “Contact Sensor” is what your ultrasonic sensor will update, based on the state of your garage door. This is the correct capability for showing the status of a door. Other SmartApps that typically work with doors will be looking for this capability.

The “Switch” is just a digital output I added back into your sketch as an example.

Where the “Contact Sensor” only transmits data to the cloud, the “Switch” is just the opposite, receiving data from the cloud (although it also sends to the cloud its status as a confirmation that the request was received and acted upon.)

Note: While I do have a HC-SR04 ultrasonic distance sensor, I could not seem to get it working at 3.3v provided by the ESP8266. Therefore, you will need to debug any of that device’s specific logic.

Here is the sketch

//*****************************************************************************
/// @file
/// @brief
///   Arduino SmartThings Ethernet ESP8266 WiFi On/Off with LED Example 
///
///   Revised by Dan Ogorchock on 2017-02-11 to work with new "SmartThings v2.0" Library
///
///   Notes: The NodeMCU ESP communicates via WiFi to your home network router,
///          then to the ST Hub, and eventually to the ST cloud servers.
///
///
//*****************************************************************************

#include <SmartThingsESP8266WiFi.h>
//#include <ESP8266WiFi.h>  //should not be needed - DanO
//#include <SoftwareSerial.h> //should not be needed here - DanO

//*****************************************************************************
// Pin Definitions    | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                    V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
//******************************************************************************************
//NodeMCU ESP8266 Pin Definitions (makes it much easier as these match the board markings)
//******************************************************************************************

#define D6 12
#define D7 13
#define D8 15 //DanO

//Defining Echo/Trig Pin
#define echoPin D6 // Echo Pin
#define trigPin D7 // Trigger Pin

#define switchPin D8 //Digital Output Pin - DanO

//*****************************************************************************
// Global Variables   | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                    V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
SmartThingsCallout_t messageCallout;    // call out function forward decalaration
//Application Global Variables
const double MIN_HEIGHT = 25; //in INCHES
const int DELAY_SEC = 15; //in seconds (to facilitate debugging!) - DanO
boolean isOpen = false;
long duration, inches, cm;
//******************************************************************************************
//ESP8266 WiFi Information    CHANGE THIS INFORMATION ACCORDINGLY FOR YOUR NETWORK!
//******************************************************************************************
String str_ssid     = "WIFI";                                   //  <---You must edit this line!
String str_password = "PASSWORD";                               //  <---You must edit this line!
IPAddress ip(192, 168, 1, 15);       // Device IP Address       //  <---You must edit this line!
IPAddress gateway(192, 168, 1, 1);    //router gateway          //  <---You must edit this line!
IPAddress subnet(255, 255, 255, 0);   //LAN subnet mask         //  <---You must edit this line!
IPAddress dnsserver(192, 168, 1, 1);  //DNS server              //  <---You must edit this line!
const unsigned int serverPort = 8090; // port to run the http server on

// Smartthings Hub Information
IPAddress hubIp(192, 168, 1, 201);    // smartthings hub ip     //  <---You must edit this line!
const unsigned int hubPort = 39500;   // smartthings hub port


//Create a SmartThings Ethernet ESP8266WiFi object
st::SmartThingsESP8266WiFi smartthing(str_ssid, str_password, ip, gateway, subnet, dnsserver, serverPort, hubIp, hubPort, messageCallout);

bool isDebugEnabled;    // enable or disable debug in this example
unsigned long previousMillis = 0; //needed for new timing mechanism - DanO


//*****************************************************************************
// API Functions    | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                  V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
void setup()
{
  // setup default state of global variables
  isDebugEnabled = true;

  if (isDebugEnabled)
  { // setup debug serial port
    Serial.begin(9600);         // setup serial with a baud rate of 9600
    Serial.println("");
    Serial.println("setup..");  // print out 'setup..' on start
  }
  
  // setup hardware pins 
  //HC-SR04 Setup
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(switchPin, OUTPUT);     // define PIN_LED as an output

  //Run the SmartThings init() routine to make sure the ThingShield is connected to the ST Hub
  smartthing.init();
  
  //synch up the ST cloud 
  off();       // Set the digout to "off" and update ST Cloud.
  
  sendData(isOpen);  //Added here for debugging purposes.  May want to remove this before deploying!
}

//*****************************************************************************
void loop()
{
  smartthing.run();
  if (millis() - previousMillis > DELAY_SEC * 1000)
  {
    previousMillis = millis();
    checkSensor();
  }

}

//*****************************************************************************
// Local Functions  | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                  V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
void checkSensor()
{
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  inches = microsecondsToInches(duration);
  if((inches < MIN_HEIGHT) && (!isOpen)) {
    isOpen = true;
  }
  if((inches > MIN_HEIGHT) && (isOpen)) {
    isOpen = false;
  }
  if(isDebugEnabled)
  {
    Serial.print("Inches: ");
    Serial.println(inches);
    Serial.print("Garage Door Status: ");
    Serial.print("isOpen = ");
    Serial.println(isOpen);
  } 
   
  sendData(isOpen);
  
}

//*****************************************************************************
void sendData(boolean status)
{
  if(status)
  {
    if(isDebugEnabled)
    {
      Serial.println("Send: contact open");
    }
    smartthing.send("contact open");        // send message to cloud
  }
  else
  {
    if(isDebugEnabled)
    {
      Serial.println("Send: contact closed");
    }
    smartthing.send("contact closed");        // send message to cloud
  }
}

//*****************************************************************************
void on()
{
  digitalWrite(switchPin, HIGH); // turn output on

  if(isDebugEnabled)
  {
    Serial.println("Send: switch on");
  }
  
  smartthing.send("switch on");        // send message to cloud
}

//*****************************************************************************
void off()
{
  digitalWrite(switchPin, LOW); // turn output off

  if(isDebugEnabled)
  {
    Serial.println("Send: switch off");
  }

  smartthing.send("switch off");       // send message to cloud
}

//*****************************************************************************
void messageCallout(String message)
{
  // if debug is enabled print out the received message
  if (isDebugEnabled)
  {
    Serial.print("Received message: '");
    Serial.print(message);
    Serial.println("' ");
  }

  // if message contents equals to 'on' then call on() function
  // else if message contents equals to 'off' then call off() function
  if (message.equals("switch on"))
  {
    on();
  }
  else if (message.equals("switch off"))
  {
    off();
  }
}

long microsecondsToInches(long microseconds) {
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

And here is the Device Handler

/**
 *  PeterSun_Ethernet.device.groovy
 *
 *  Copyright 2017 Dan G Ogorchock 
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 *  Change History:
 *
 *    Date        Who            What
 *    ----        ---            ----
 *    2017-02-08  Dan Ogorchock  Original Creation
 *    2017-02-12  Dan Ogorchock  Modified to work with Ethernet based devices instead of ThingShield
 *    2017-02-26  Dan Ogorchock  Modified for Peter Sun's project
 *
 */
 
metadata {
	definition (name: "PeterSunEthernet", namespace: "ogiewon", author: "Dan Ogorchock") {
		capability "Configuration"
		capability "Switch"
		capability "Sensor"
		capability "Contact Sensor"

	}

    simulator {
 
    }

    // Preferences
	preferences {
		input "ip", "text", title: "Arduino IP Address", description: "ip", required: true, displayDuringSetup: true
		input "port", "text", title: "Arduino Port", description: "port", required: true, displayDuringSetup: true
		input "mac", "text", title: "Arduino MAC Addr", description: "mac", required: true, displayDuringSetup: true
	}

	// Tile Definitions
	tiles {
         standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
			state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
			state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
		}
		standardTile("contact", "device.contact", width: 1, height: 1) {
			state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
			state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
		}
		standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
			state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
		}

        main(["switch","contact"])
        details(["switch","contact","configure"])
	}
}

// parse events into attributes
def parse(String description) {
	//log.debug "Parsing '${description}'"
	def msg = parseLanMessage(description)
	def headerString = msg.header

	if (!headerString) {
		//log.debug "headerstring was null for some reason :("
    }

	def bodyString = msg.body

	if (bodyString) {
        log.debug "BodyString: $bodyString"
    	def parts = bodyString.split(" ")
    	def name  = parts.length>0?parts[0].trim():null
    	def value = parts.length>1?parts[1].trim():null

    	def result = createEvent(name: name, value: value)

    	log.debug result

    return result
	}
}

private getHostAddress() {
    def ip = settings.ip
    def port = settings.port

	log.debug "Using ip: ${ip} and port: ${port} for device: ${device.id}"
    return ip + ":" + port
}


def sendEthernet(message) {
	log.debug "Executing 'sendEthernet' ${message}"
	new physicalgraph.device.HubAction(
    	method: "POST",
    	path: "/${message}?",
    	headers: [ HOST: "${getHostAddress()}" ]
	)
}

// handle commands

def on() {
	log.debug "Executing 'switch on'"
	sendEthernet("switch on")
}

def off() {
	log.debug "Executing 'switch off'"
	sendEthernet("switch off")
}


def configure() {
	log.debug "Executing 'configure'"
	updateDeviceNetworkID()
}

def updateDeviceNetworkID() {
	log.debug "Executing 'updateDeviceNetworkID'"
    if(device.deviceNetworkId!=mac) {
    	log.debug "setting deviceNetworkID = ${mac}"
        device.setDeviceNetworkId("${mac}")
	}
}

def updated() {
	if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 5000) {
		state.updatedLastRanAt = now()
		log.debug "Executing 'updated'"
    	runIn(3, updateDeviceNetworkID)
	}
	else {
		log.trace "updated(): Ran within last 5 seconds so aborting."
	}
}

@psun03

Sooooo… did the files I provided resolve the issue? Were you able to get accurate measurements from the ultrasonic sensor?

Thanks for the code… sorry… getting caught up on some other stuff… i plan on trying sometime this week… i will let you know… :slight_smile:

:+1: Works like a charm… thanks for the help…

1 Like

Glad hear it’s working. Can you explain how you’ve wired the SR04 sensor to your ESP8266? I am curious if you’re using 3.3v or 5v to power the sensor?

I have one of these babies… https://www.wemos.cc/product/d1.html

It is basically an ESP8266/Arduino UNO on one board. So basically, I have 5v available for projects. They are like 6 bucks on ebay. I never had any luck adding an ESP8266 to an Arduino UNO or patients to figure them out. I have like 5 ESP8266 sitting in my closet. The Wemos works pretty well. I have done some other projects with it.

Ah, that makes sense. So you are using 5v for the ultrasonic sensor. That’s a very nice board, in a very familiar form-factor! :wink:

Hi Dan,

I am new to smartthings and learning a ton from your Handler and arduino code. I am using a Wemos D1 and I would like to have multiple switch tiles in the same handler that control different I/O’s on the Wemos. Not sure if thats the most practical way to do this or not. Do you have any advice or suggestions? Is this something that is possible or is there a different method i should look into?

Thanks for the help!

Craig

Craig,

I haven’t used a Wemos D1, but it should run ST_Anything without too much effort. I believe others have successfully done so already. Controlling the GPIO pins on a microcontroller is what ST_Anything does best! You should be able to simply edit just the Arduino sketch to support the devices you want to attach to the Wemos D1 and be good to go! The ST_Anything SmartThings Groovy Device Handler code is now generic so you really just need to add my repository to your ST IDE account and install/publish the device handlers. Very little code for you to write.

Take a look at the main ST_Anything project discussion below, as well as read through my GitHub ReadMe file to get started. Just be sure to follow the instructions for the NodeMCU ESP8266 as that is the closest device to a Wemos D1 (i.e. the same micocontroller.) In the Arduino IDE though, be sure to select the Wemos D1 as your board type.

Just a heads up: Wemos D1 has two revisions, with different board types and pinouts. I have the v1 board here, and it took ages to figure out which pins were where.

Incidentally I had a quick look at ST_Anything when I was developing my 433MHz bridge, but couldn’t quite see where to start configuring Device Handlers. Are there any examples for this kind of thing?

Currently I’m running a web server on the D1 which can be triggered from a ST virtual light switch

Hi All…

It’s me again… like a broken record …( Old School )

If anyone has an Arduino ThingShield available for sale, please let me know
still looking for a couple units.

Thank you for any assistance

Ben

Dan
Should this sketch and DTH work with the latest version of your integration?
I would like to use this setup to check which of my garages are occupied. I set up a webCoRE piston using SmartThings presence sensors to determine which garage door should open when I get home, but they are extremely unreliable - they are seldom picked up by the hub when they are in a vehicle (and the batteries are always flat).
I wrote the sketch to a NodeMCU and connected an ultrasonic sensor to it, but the child device doesn’t get created. I’m able to ping the NodeMCU and made sure that I enetered the Mac address correctly in the Device Settings.
I don’t know if there is a way to troubleshoot the ultrasonic sensor to check if it is sending info to the NodeMCU, but I suppose for that to happen, the child device needs to be created first. I did add the DTH to the ST IDE.
Thank you

Ah Hendre… What are you up to now? You’re digging up an old thread for sure that pre-dates many of the improvements that I have made to ST_Anything over the past year. The sketch included above was written for a very specific user’s needs and may or may not work still. The sketch and DTH are a matched set in this case, and pre-date the use of the Parent/Child Device Handlers.

What are you attempting to do now?

Why not post your questions in the main ST_Anything thread? It helps to keep the information in one place and it is easier for me to help you if you stick with the current software.

:innocent: Sorry Dan! I was worried that your stomach is going to turn when you see my question. :sweat_smile:

Hi and thanks for the great work. It seems that it worked for other users here and I wonder if it still works. On my side I just can’t get the hub to receive any data from the smartthing.send(string) command. It simply won’t work this way. It works only from hub to device but not from device to hub. Can you confirm that it still work for you? I’m asking because I heard smartthings stopped allowing lan communication on port 39500.

UPDATE: I simply forgot to give the virtual device an ID matching the mac address of my device! :smiley:

1 Like

ogiewon,

I try to setup esp8266 garage opener and ultrasonic sensor code you have. I flash esp8266 and add device handler code provided by you. How do i get it to show up on the app? i try to add device but get “We’re sorry, but you are not authorized to perform the requested operation.” I try to add a thing but it not showing up.

Read the detailed instructions in the ST_Anything ReadMe in the Guthub repository. It has step by step directions that will help you to get things up and running.