[Release] HubDuino v1.1.9 - Hubitat to Arduino / ESP8266 / ESP32 / ThingShield Integration (ST_Anything)

@kilowatts is that a Lightify dimmer switch in your video to control the blinds?

Yep! Works pretty well.

@ogiewon I am trying to get a servo running on an ESP-01. I am encountering an issue where it crashes.

I am using the ESP8266 2.3.0 version with Arduino IDE version 1.8.8

Here is the bootup and crash:

Everything: init started
Everything: Free RAM = 45664

Initializing ESP8266 WiFi network.  Please be patient...
Attempting to connect to WPA SSID: xxxxx
.......

Enter the following three lines of data into ST App on your phone!
localIP = 192.168.30.8
serverPort = 8090
MAC Address = xxxx

SSID = xxxx
PASSWORD = xxxx
hubIP = 192.168.30.5
hubPort = 39501
RSSI = -62
hostName = ESP8266_xxxx

SmartThingsESP8266WiFI: Intialized

Disabling ESP8266 WiFi Access Point

ArduinoOTA Ready
IP address: 192.168.30.8
ArduionOTA Host Name: ESP8266_xxxx

Everything: init ended
Everything: Free RAM = 44544
Everything: adding executor named servo1
Everything: Free RAM = 44544
Everything: initDevices started
Everything: Free RAM = 44544
EX_Servo:: Servo motor angle set to 89
Everything: Sending: servo1 49
Everything: initDevices ended
Everything: Free RAM = 44648
Device: Destroyed Device ID: servo1
Everything: Received: servo1 40

Exception (28):
epc1=0x40208e6f epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

ctx: cont 
sp: 3ffef890 end: 3ffefb70 offset: 01a0

>>>stack>>>
3ffefa30:  00000010 00000001 3ffefaa0 40207f29  
3ffefa40:  00000006 3ffefad8 3ffefaa0 4020805d  
3ffefa50:  3fff1364 00000009 3ffeea84 402075bd  
3ffefa60:  3ffe87f4 3ffefad8 00000000 402055d6  
3ffefa70:  00000020 3ffeea84 3ffeea84 402076b8  
3ffefa80:  3ffefc6c 00000015 3ffefad8 0000000a  
3ffefa90:  3ffe8af4 00000000 3ffefad8 4020566b  
3ffefaa0:  3fff125c 0000000f 00000006 40208014  
3ffefab0:  3ffe8af4 00000005 40205614 40202c28  
3ffefac0:  3ffe85f8 00000000 000003e8 00009a4d  
3ffefad0:  3fff0c78 00000000 3fff1364 0000000f  
3ffefae0:  00000009 00000000 00000000 00000000  
3ffefaf0:  3fff106c 0000000f 00000000 3fff1054  
3ffefb00:  0000000f 00000009 3fff138c 0000006f  
3ffefb10:  00000069 00000000 00000000 00000000  
3ffefb20:  00000000 3ffe87e8 051ea8c0 3ffeeb40  
3ffefb30:  3fffdad0 00000000 3ffeeb39 4020585c  
3ffefb40:  00000000 00000000 3ffeeb39 402020a3  
3ffefb50:  3fffdad0 00000000 3ffeeb39 40208848  
3ffefb60:  feefeffe feefeffe 3ffeeb50 40100718  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(1,7)


 ets Jan  8 2013,rst cause:4, boot mode:(1,7)

wdt reset

Here is the code associated with it.

 //******************************************************************************************
//  File: ST_Anything_Multiples_ESP01WiFi.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 ESP8266-01 (ESP-01) 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 ESP-01's WiFi.
//    
//            ST_Anything_Multiples implements the following ST Capabilities in multiples of 1 as a demo of what is possible with a single ESP-01
//              - 1 x Contact Sensor device (used to monitor magnetic door sensors)
//              - 1 x Motion devices (used to detect motion)
//
//  Note:  The tiny ESP-01 only has 2 GPIO pins, so this example is somewhat limited.  Use the ST_ANything_Multiples_ESP8266WiFi.ino example to see 
//         what else is possible.  As long as you only try using 2 pins, you can use them for whatever you'd like.
//
//  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-02-21  Dan Ogorchock  New example specifically for running everythin on a ESP-01 (no Arduino required!)
//    2017-04-24  Dan Ogorchock  Updated for use with new v2.5 Parent/Child Device handlers
//    2018-02-09  Dan Ogorchock  Added support for Hubitat Elevation Hub
//
//******************************************************************************************
//******************************************************************************************
// 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 <EX_Servo.h>       //Implements an Executor (EX) via a Servo

//******************************************************************************************
//Define which Arduino Pins will be used for each device
//******************************************************************************************

#define PIN_SERVO               0

//******************************************************************************************
//ESP8266 WiFi Information
//******************************************************************************************
String str_ssid     = "xxxx";                           //  <---You must edit this line!
String str_password = "xxxx";                   //  <---You must edit this line!
IPAddress ip(192, 168, 30, 8);       //Device IP Address       //  <---You must edit this line!
IPAddress gateway(192, 168, 30, 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, 30, 1);  //DNS server              //  <---You must edit this line!
const unsigned int serverPort = 8090; // port to run the http server on

// Smartthings / Hubitat Hub TCP/IP Address
IPAddress hubIp(192, 168, 30, 5);    // smartthings/hubitat hub ip //  <---You must edit this line!

// SmartThings / Hubitat Hub TCP/IP Address: UNCOMMENT line that corresponds to your hub, COMMENT the other
//const unsigned int hubPort = 39500;   // smartthings hub port
const unsigned int hubPort = 39501;   // hubitat 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 ESP-01
  //  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
 
  //Interrupt Sensors 

  
  //Executors
  st::EX_Servo executor1(F("servo1"), PIN_SERVO, 90, true, 1000);
  
  //*****************************************************************************
  //  Configure debug print output from each main class 
  //*****************************************************************************
  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
  //*****************************************************************************

  
  //*****************************************************************************
  //Add each executor to the "Everything" Class
  //*****************************************************************************
  st::Everything::addExecutor(&executor1);
    
  //*****************************************************************************
  //Initialize each of the devices which were added to the Everything Class
  //*****************************************************************************
  st::Everything::initDevices();

  //*****************************************************************************
  //Initialize Watchdog Timer to detect lockups and automatically restart the MCU
  //*****************************************************************************
  wdt_enable(WDTO_8S);
}

//******************************************************************************************
//Arduino Loop() routine
//******************************************************************************************
void loop()
{
  //*****************************************************************************
  //Reset Watchdog Timer to let is know everything is running fine
  //*****************************************************************************
  wdt_reset();
  
  //*****************************************************************************
  //Execute the Everything run method which takes care of "Everything"
  //*****************************************************************************
  st::Everything::run();
}

Try commenting out the following lines regarding the Watchdog Timer. I added this in an attempt to automatically reset the ESP8266 in the event it got lucked up somehow. Unfortunately, it does not help with the lock up I was hoping this would resolve. So, I am wondering if it might be causing an issue for the ESP01. It's worth a try!

setup()

  //*****************************************************************************
  //Initialize Watchdog Timer to detect lockups and automatically restart the MCU
  //*****************************************************************************
  //(commented out for testing) wdt_enable(WDTO_8S);

loop()

  //*****************************************************************************
  //Reset Watchdog Timer to let is know everything is running fine
  //*****************************************************************************
 //(commented out for testing) wdt_reset();

Is this normal?

Device: Destroyed Device ID: servo1

I've never seen that before... where are you seeing that? Within the Arduino IDE? Or within the Live Logging?

Did you remove the HubDuino Parent device? Doing so will remove all of its child devices as well. Perhaps that what you're seeing?

I see that in the serial monitor of the Arduino IDE

Hmmm... Is that after you made the suggested changes?

Before and after... You can see it in the log in my original post.

Everything: init ended
Everything: Free RAM = 44544
Everything: adding executor named servo1
Everything: Free RAM = 44544
Everything: initDevices started
Everything: Free RAM = 44544
EX_Servo:: Servo motor angle set to 89
Everything: Sending: servo1 49
Everything: initDevices ended
Everything: Free RAM = 44648
**Device: Destroyed Device ID: servo1**
Everything: Free Ram = 44648
Everything: Free Ram = 44648

I tried to bold the line...

That's strange... I found the code that is printing it... in Device.cpp

	//destructor
	Device::~Device()
	{
		if(debug)
		{
			Serial.print(F("Device: Destroyed Device ID: "));
			Serial.println(getName());
		}
	}

It is only called when the C++ object is destroyed... But I have never seen the destructor ever called. I wonder if it happen as part of the ESP01 reset somehow? Or, does it cause the reset...

Have you tried running the same sketch (different pin maybe) on a NodeMCU ESP8266 board?

I am going to try running your sketch here... might take me a while to dig out an ESP01 board/programmer circuit... It's been a long time since I messed with one of those... :wink:

I moved the servo to Pin 1 and now it appears to lock up on the initialization...

Everything: init ended
Everything: Free RAM = 44544
Everythi

I have reproduced the problem here on a NodeMCU ESP8266 board. I am not sure what is going on...

I just downloaded the code to a node mcu 8266 and I get the same output in the log.

from nodemcu:

Everything: init ended
Everything: Free RAM = 44544
Everything: adding executor named servo1
Everything: Free RAM = 44544
Everything: initDevices started
Everything: Free RAM = 44544
EX_Servo:: Servo motor angle set to 89
Everything: Sending: servo1 49
Everything: initDevices ended
Everything: Free RAM = 44648
Device: Destroyed Device ID: servo1
Everything: Free Ram = 44648

Well thats a good thing. Reproduceable on three devices.

I have found the issue (with my son's help!) When you declared your Servo device in the setup() routine, you did not declare it as 'static'. So, when the object went out of scope, it was destroyed (thus the destructor was called.)

Change you setup() code as follows

  //Executors
  static st::EX_Servo executor1(F("servo1"), PIN_SERVO, 90, true, 1000);

trying it now! You guys are awesome!

That was it! Thank you so much!!

1 Like

Dan, I'm starting planning on a project to add zone control to my HVAC system. I will use EX_Servo to drive servos attached to the dampers that are already installed in each of my register ducts. I set up a test Hubduino to validate my understanding of EX_Servo function. It works in my initial trials, but I have a couple questions, and a few proposals.

My first question: for EX_Servo as currently implemented: why is the level range allowed in the Hubitat Device 0-100, while EX_Servo.cpp maps the level at 0-99? Trivial difference, but I'd like to understand if it is intentional, and why.

Second, the Hubitat device inputs are level and duration. Is duration intended to be an alternate way to specify time until detachment? I can't seem to find an effect of changes in this parameter, regardless of presence or omission of the servoMoveTime argument in the sketch.

My dampers rotate 90 degrees from full closed to full open, so I intend to employ a 2:1 lever ratio vs. the servos to take full advantage of the 0-100 level (0-180 degrees) range input to the device. I expect variation in the hardware installation from damper to damper which will require either tweaking the hardware one by one, or living with variation damper to damper for equivalent level settings.

If it is was just one set of hardware being implemented, remapping within EX_Servo would be a simple solution. Given 14 dampers to tweak for my application, I'm looking for a more elegant solution.

I think an efficient approach would be adding two optional arguments to EX_Servo to let users specify the angles associated with endpoints, level 0 and level 100. Default could be 0 and 180 degrees as is now standard. This would help endpoint tweaking plus correct those unfortunate situations where the hardware setup is backwards in direction of desired movement. This change would be further enhanced if the start position specified as a sketch parameter was a level instead of an angle.

This feature would allow level 0 and level 100 to be very intuitive as fully closed and fully open. I think this functionality would also benefit those that are using EX_Servo for blinds.

An additional level of sophistication would be allowing arguments for non-linear mapping similar to PS_Voltage. For applications like damper control, this would allow the 0-100 level mapping to more closely tie to airflow, which is not linear with respect to damper angle.

I noticed comments about blind applications where the sudden movement of blinds can startle people. I think altering the implementation of the servoMoveTime parameter could solve this problem. Currently it is just a delay to allow motion of the servo before detachment. A more useful implementation would directly control the duration of the servo adjustment, and then detach if desired. Blinds adjusting over 5-10 seconds would likely be so quiet that they would not be noticed. The complication is needing to output multiple small step changes in servo position. I'm not sure if this can be implemented without causing timing issues with other tasks.

These updates might be within my coding capability, but I want to see what you think of the ideas. Based on past discussions, you'll probably have this implemented before I wake up tomorrow.

Jeff

1 Like

I am working on the same exact thing, only I am controlling the damper on the registers because my dampers within the ducts effect multiple rooms.

I like your suggestions!

1 Like

Jeff,

I like your ideas and they are definitely things I have considered as well. I actually added the servo motor support for a ST user a few months ago who wanted to make his own smart vents. I whipped the EX_Servo class together quickly just to help him get started.

I think the idea of allowing the user to adjust the scaling of dim levels (0 to 100) to servo degress (0 to 180) makes perfect sense. The question is whether this should be done when the device is created in the sketch...or...in the Hubitat Driver code. Doing it in the Driver has the advantage of being able to fine tune the scaling without having to reprogram the microcontroller. Thoughts?

The hard one is figuring out a nice clean method for handling the servo motion over a given time period. This one is a little more tricky as the Executors (EX) in ST_Anything don't typically get called every pass through the loop() function like the Interrupt Sensors (IS) do. This was simply because we assumed that Executors would only need to be called when a change was required. So, we need a mechanism to repeatedly call into the EX_Servo class to make the small incremental movements over a period of time, without using blocking calls. The blocking calls tend to mess up the network communications, so I try to avoid them as much as possible. Even the current delay() that I have in the EX_Servo to allow the movement to complete and then power the servo off (to prevent buzzing) annoys me knowing it is in there! So, enhancing the EX_Servo class to be able to perform smoother motion moves is a very good idea. We just need to figure out how to do it cleanly.

Oh, and as for this one...

I honestly don't recall! :slight_smile: We can change it to 0 - 100 and it should be fine.

1 Like