Announcing the "ST_Anything" Arduino/ThingShield Project

Continuing the discussion from Announcing the "ST_Anything" Arduino/ThingShield Project:

Hello Dan
Thanks for that, I have another question, I 've been trying to modify your project to have just 4 relays, so far everything is working well, I have control of each relay and the push buttons work perfectly even if the hub is down. Nevertheless, I tried to create an app to turn on the relays when motion my sensor detects that the door is open and the app doesn’t work any idea what could be the problem. I am wondering if I’m able to use other devices to trigger the relays


this the groovy smart app
/**

  • ST_Anything_Relays Multiplexer - ST_Anything_Relays_Multiplexer.smartapp.groovy
  • Copyright 2015 Daniel 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

  • 2015-03-27 Dan Ogorchock Original Creation

*/
definition(
name: “ST_Anything_Relays Multiplexer”,
namespace: “ogiewon”,
author: “Daniel Ogorchock”,
description: “Virtual Switches to Arduino Relays Multiplexer/Demultiplexer”,
category: “My Apps”,
iconUrl: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png”,
iconX2Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”,
iconX3Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”)

preferences {
section(“Select the Relays (Virtual Switch devices)”) {
input “virtual_switch_1”, title: “Virtual Switch for Relay 1”, “capability.switch”, required: true
input “virtual_switch_2”, title: “Virtual Switch for Relay 2”, “capability.switch”, required: false
input “virtual_switch_3”, title: “Virtual Switch for Relay 3”, “capability.switch”, required: false
input “virtual_switch_4”, title: “Virtual Switch for Relay 4”, “capability.switch”, required: false

}

section("Select the Arduino ST_Anything_Relays device") {
	input "arduino", "capability.switch", required: true
}    

}

def installed() {
log.debug “Installed with settings: ${settings}”
subscribe()
}

def updated() {
log.debug “Updated with settings: ${settings}”
unsubscribe()
subscribe()
}

def subscribe() {

    subscribe(arduino, "switch1.on", switch1on)
    subscribe(arduino, "switch1.off", switch1off)
    subscribe(virtual_switch_1, "switch.on", relay1on)
    subscribe(virtual_switch_1, "switch.off", relay1off)

if (virtual_switch_2) {
    subscribe(arduino, "switch2.on", switch2on)
    subscribe(arduino, "switch2.off", switch2off)
    subscribe(virtual_switch_2, "switch.on", relay2on)
    subscribe(virtual_switch_2, "switch.off", relay2off)
}

if (virtual_switch_3) {
    subscribe(arduino, "switch3.on", switch3on)
    subscribe(arduino, "switch3.off", switch3off)
    subscribe(virtual_switch_3, "switch.on", relay3on)
    subscribe(virtual_switch_3, "switch.off", relay3off)
}

if (virtual_switch_4) {
    subscribe(arduino, "switch4.on", switch4on)
    subscribe(arduino, "switch4.off", switch4off)
    subscribe(virtual_switch_4, "switch.on", relay4on)
    subscribe(virtual_switch_4, "switch.off", relay4off)
}

if (virtual_switch_5) {
    subscribe(arduino, "switch5.on", switch5on)
    subscribe(arduino, "switch5.off", switch5off)
    subscribe(virtual_switch_5, "switch.on", relay5on)
    subscribe(virtual_switch_5, "switch.off", relay5off)
}

if (virtual_switch_6) {
    subscribe(arduino, "switch6.on", switch6on)
    subscribe(arduino, "switch6.off", switch6off)
    subscribe(virtual_switch_6, "switch.on", relay6on)
    subscribe(virtual_switch_6, "switch.off", relay6off)
}

if (virtual_switch_7) {
    subscribe(arduino, "switch7.on", switch7on)
    subscribe(arduino, "switch7.off", switch7off)
    subscribe(virtual_switch_7, "switch.on", relay7on)
    subscribe(virtual_switch_7, "switch.off", relay7off)
}

if (virtual_switch_8) {
    subscribe(arduino, "switch8.on", switch8on)
    subscribe(arduino, "switch8.off", switch8off)
    subscribe(virtual_switch_8, "switch.on", relay8on)
    subscribe(virtual_switch_8, "switch.off", relay8off)
}

if (virtual_switch_9) {
    subscribe(arduino, "switch9.on", switch9on)
    subscribe(arduino, "switch9.off", switch9off)
    subscribe(virtual_switch_9, "switch.on", relay9on)
    subscribe(virtual_switch_9, "switch.off", relay9off)
}

if (virtual_switch_10) {
    subscribe(arduino, "switch10.on", switch10on)
    subscribe(arduino, "switch10.off", switch10off)
    subscribe(virtual_switch_10, "switch.on", relay10on)
    subscribe(virtual_switch_10, "switch.off", relay10off)
}

if (virtual_switch_11) {
    subscribe(arduino, "switch11.on", switch11on)
    subscribe(arduino, "switch11.off", switch11off)
    subscribe(virtual_switch_11, "switch.on", relay11on)
    subscribe(virtual_switch_11, "switch.off", relay11off)
}

if (virtual_switch_12) {
    subscribe(arduino, "switch12.on", switch12on)
    subscribe(arduino, "switch12.off", switch2off)
    subscribe(virtual_switch_12, "switch.on", relay12on)
    subscribe(virtual_switch_12, "switch.off", relay12off)
}

if (virtual_switch_13) {
    subscribe(arduino, "switch13.on", switch13on)
    subscribe(arduino, "switch13.off", switch13off)
    subscribe(virtual_switch_13, "switch.on", relay13on)
    subscribe(virtual_switch_13, "switch.off", relay13off)
}

if (virtual_switch_14) {
    subscribe(arduino, "switch14.on", switch14on)
    subscribe(arduino, "switch14.off", switch14off)
    subscribe(virtual_switch_14, "switch.on", relay14on)
    subscribe(virtual_switch_14, "switch.off", relay14off)
}

if (virtual_switch_15) {
    subscribe(arduino, "switch15.on", switch15on)
    subscribe(arduino, "switch15.off", switch15off)
    subscribe(virtual_switch_15, "switch.on", relay15on)
    subscribe(virtual_switch_15, "switch.off", relay15off)
}

if (virtual_switch_16) {
    subscribe(arduino, "switch16.on", switch16on)
    subscribe(arduino, "switch16.off", switch16off)
    subscribe(virtual_switch_16, "switch.on", relay16on)
    subscribe(virtual_switch_16, "switch.off", relay16off)
}

}

//--------------- Relay 1 handlers ---------------
def switch1on(evt)
{
if (virtual_switch_1.currentValue(“switch”) != “on”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping On Virtual Switch to match Arduino”
virtual_switch_1.on()
}
}
def switch1off(evt)
{
if (virtual_switch_1.currentValue(“switch”) != “off”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping Off Virtual Switch to match Arduino”
virtual_switch_1.off()
}
}
def relay1on(evt)
{
if (arduino.currentValue(“switch1”) != “on”) {
log.debug “relay1event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning On Arduino Relay to match Virtual Switch”
arduino.switch1on()
}
}
def relay1off(evt)
{
if (arduino.currentValue(“switch1”) != “off”) {
log.debug “relay1event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning Off Arduino Relay to match Virtual Switch”
arduino.switch1off()
}
}

//--------------- Relay 2 handlers ---------------
def switch2on(evt)
{
if (virtual_switch_2.currentValue(“switch”) != “on”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping On Virtual Switch to match Arduino”
virtual_switch_2.on()
}
}
def switch2off(evt)
{
if (virtual_switch_2.currentValue(“switch”) != “off”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping Off Virtual Switch to match Arduino”
virtual_switch_2.off()
}
}
def relay2on(evt)
{
if (arduino.currentValue(“switch2”) != “on”) {
log.debug “relay2event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning On Arduino Relay to match Virtual Switch”
arduino.switch2on()
}
}
def relay2off(evt)
{
if (arduino.currentValue(“switch2”) != “off”) {
log.debug “relay2event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning Off Arduino Relay to match Virtual Switch”
arduino.switch2off()
}
}

//--------------- Relay 3 handlers ---------------
def switch3on(evt)
{
if (virtual_switch_3.currentValue(“switch”) != “on”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping On Virtual Switch to match Arduino”
virtual_switch_3.on()
}
}
def switch3off(evt)
{
if (virtual_switch_3.currentValue(“switch”) != “off”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping Off Virtual Switch to match Arduino”
virtual_switch_3.off()
}
}
def relay3on(evt)
{
if (arduino.currentValue(“switch3”) != “on”) {
log.debug “relay3event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning On Arduino Relay to match Virtual Switch”
arduino.switch3on()
}
}
def relay3off(evt)
{
if (arduino.currentValue(“switch3”) != “off”) {
log.debug “relay3event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning Off Arduino Relay to match Virtual Switch”
arduino.switch3off()
}
}

//--------------- Relay 4 handlers ---------------
def switch4on(evt)
{
if (virtual_switch_4.currentValue(“switch”) != “on”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping On Virtual Switch to match Arduino”
virtual_switch_4.on()
}
}
def switch4off(evt)
{
if (virtual_switch_4.currentValue(“switch”) != “off”) {
log.debug “arduinoevent($evt.name: $evt.value: $evt.deviceId)”
log.debug “Flipping Off Virtual Switch to match Arduino”
virtual_switch_4.off()
}
}
def relay4on(evt)
{
if (arduino.currentValue(“switch4”) != “on”) {
log.debug “relay4event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning On Arduino Relay to match Virtual Switch”
arduino.switch4on()
}
}
def relay4off(evt)
{
if (arduino.currentValue(“switch4”) != “off”) {
log.debug “relay4event($evt.name: $evt.value: $evt.deviceId)”
log.debug “Turning Off Arduino Relay to match Virtual Switch”
arduino.switch4off()
}
}

AND THIS IS THE DEVICE HANDLER
/**

  • ST_Anything_Relays - ST_Anything_Relays.device.groovy
  • Copyright 2015 Daniel 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

  • 2015-03-27 Dan Ogorchock Original Creation

*/

metadata {
definition (name: “ST_Anything_Relays”, namespace: “ogiewon”, author: “Daniel Ogorchock”) {
capability “Actuator”
capability “Switch”

	attribute "switch1", "string"
	attribute "switch2", "string"
	attribute "switch3", "string"
	attribute "switch4", "string"
    
	
	command "switch1on"
	command "switch1off"
	command "switch2on"
	command "switch2off"
	command "switch3on"
	command "switch3off"
	command "switch4on"
	command "switch4off"

}

simulator {
}


// tile definitions
tiles {

    standardTile("switch1", "device.switch1", width: 1, height: 1, canChangeIcon: true) {
		state "off", label: '${name}', action: "switch1on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
		state "on", label: '${name}', action: "switch1off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
	}

    standardTile("switch2", "device.switch2", width: 1, height: 1, canChangeIcon: true) {
		state "off", label: '${name}', action: "switch2on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
		state "on", label: '${name}', action: "switch2off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
	}
    
    standardTile("switch3", "device.switch3", width: 1, height: 1, canChangeIcon: true) {
		state "off", label: '${name}', action: "switch3on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
		state "on", label: '${name}', action: "switch3off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
	}
    
    standardTile("switch4", "device.switch4", width: 1, height: 1, canChangeIcon: true) {
		state "off", label: '${name}', action: "switch4on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
		state "on", label: '${name}', action: "switch4off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
	}

           main (["switch1"])
    details (["switch1","switch2","switch3","switch4"])
}

}

//Map parse(String description) {
def parse(String description) {
def msg = zigbee.parse(description)?.text
log.debug “Parse got ‘${msg}’”

def parts = msg.split(" ")
def name  = parts.length>0?parts[0].trim():null
def value = parts.length>1?parts[1].trim():null

name = value != "ping" ? name : null

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

log.debug result

return result

}

def switch1on() {
log.debug “Executing ‘switch1on’ = ‘switch1 on’”
zigbee.smartShield(text: “switch1 on”).format()
}

def switch1off() {
log.debug “Executing ‘switch1off’ = ‘switch1 off’”
zigbee.smartShield(text: “switch1 off”).format()
}

def switch2on() {
log.debug “Executing ‘switch2on’ = ‘switch2 on’”
zigbee.smartShield(text: “switch2 on”).format()
}

def switch2off() {
log.debug “Executing ‘switch2off’ = ‘switch2 off’”
zigbee.smartShield(text: “switch2 off”).format()
}

def switch3on() {
log.debug “Executing ‘switch3on’ = ‘switch3 on’”
zigbee.smartShield(text: “switch3 on”).format()
}

def switch3off() {
log.debug “Executing ‘switch3off’ = ‘switch3 off’”
zigbee.smartShield(text: “switch3 off”).format()
}

def switch4on() {
log.debug “Executing ‘switch4on’ = ‘switch4 on’”
zigbee.smartShield(text: “switch4 on”).format()
}

def switch4off() {
log.debug “Executing ‘switch4off’ = ‘switch4 off’”
zigbee.smartShield(text: “switch4 off”).format()
}

THANKS

Did you manually create 4 virtual switches using the code in my github? Then link those 4 virtual switches to the Arduino via the Multiplexer SmartApp.

Then, when’re asked for a switch by another SmartApp, such as SmartLighting, be sure to use one of the virtual switches, not the Arduino.

Daniel, take a look at these detailed instructions as an example of how to use the Virtual Devices and Multiplexer Apps from my github repo. Obviously you’ll want to use the “Relays” sample code instead of the “Doors” code mentioned in this post.

I just installed and configured the Ardiuno/ThingShield project to integrate my Ademco/Honeywell Vista 20P using the Ad2SmartThings from here:

My Home Alarm shows me all my Vista20P sensors and their state, along with allowing me to arm and disarm the alarm system. But those sensors are not available to use used by other SmartApps or Rules outside of the AD2SmartThigs device.

Now I want to add Virtual Contact Sensors from my Vista 20P so I can use those as triggers for rules and other SmartThings devices and SmartApps. I have read as much as I can find … and I am still confused as to how to begin. The instructions above seem like they say I need another ThingShield that uses the AT_Anything_Doors device handler (for the contact sensors, I also have Glass Break, Motion, water/temp and Smoke/Heat detectors). I am hoping there is a way for me to use the exist device handler I setup for the AD2SmartThings (That includes the latest ST_AnyThing library in the Arduino Sketch) to build the virtual devices. Any guidance on how to proceed would be greatly appreciated.

Matthew,

Looks to me like you’re trying to merge two different Arduino projects together. I wouldn’t recommend attempting that. Since you’re using the AD2SmartThings project already, I would recommend you ask users their about how they have created virtual devices to expose each door or window sensor independently.

The only portion of my ST_Anything project that AD2SmartThings is using is an improved version of the SmartThings ThingShield library that I created to support the Arduino Mega 2560 and optimize memory usage.

Dan

Thanks for the quick reply. I thought I might be stretching what I was attempting to do too far. I’ll try the AD2SmartThings path.

Thanks again.

Per a user request, I have finished adding a new class to ST_Anything call “EX_Switch_Dim” which as the ability to control both a normal digital output (on/off) and a PWM output on the Arduino from SmartThings. So, this implements the SmartThings “Switch” and “Switch Level” capabilities.

Everything has been loaded into GitHub at https://github.com/DanielOgorchock/ST_Anything/

You’ll need the new EX_Switch_Dim.cpp and EX_Switch_Dim.h files added to your local copy of the ST_Anything Arduino library. Then grab a copy of the ST_Anything_Switch_Dimmer.ino sketch and add that to your Arduino sketches folder. Finally, grab the new ST_Anything_Switch_Dimmer.device.groovy device handler and add that to your ST IDE’s Device Handlers.

Enjoy!

Dan

Cool! Thank you for continuing to add cool new features!

Thanks.

Hi, daniel.
I really tried to do this by myself but I struggle, I have expended more than a week trying to make work your code with the virtual switch but I’m doing something wrong.

  1. I created a Device Handler called ST_Anything_Relays here the code: https://www.dropbox.com/s/4xyvx4eakfq9bfx/ST_Anything_Relays.rtf?dl=0
    (its working well manually)

  2. I created a Device Handler called Virtual Switch. Here the code;
    https://www.dropbox.com/s/vlt66ez1l6hw3zn/Virtual%20Switch4.rtf?dl=0

  3. Then I created a Device called switch4 and I set it as a virtual switch in the Type* field

However, the virtual device is not associated to the relay 4 in my arduino, which is working well manually from the device called ¨relays¨ but I would like to control each relay individually.

I would appreciate if you could guide me on this I am really frustrated.
Thanks a lot!!

@danielperez505 Have you followed my detailed instructions that I pointed you to in this earlier post?

Announcing the "ST_Anything" Arduino/ThingShield Project

Also, please just use my ST_Anything_Relays example without any modification. You must create and publish the custom Device Handlers and Multiplexer SmartApp using my code from my Github repository. When you create the virtual switch devices manually, you must be sure to select the custom device handler created above, not the generic SmartThings provided “Virtual Switch” which I do not believe is compatible with my Multiplexer Apps.

Once you get things working with my code, you can then start customizing it for your particular application.

Hi Dan
All done, I followed your instructions and now everything is working well, I had a mistake in one of the names no ill play with this and let you know if I need any help
Thanks mate!

The multiplexer is a SmartApp, not a device handler. Add it to your list of user defined SmartApps in the IDE, save it, and publish it.

Then, using your phone’s SmartThings app, add the Multiplexer SmartApp to your system. During the configuration of the SmartApp, you will select up to 16 virtual switch devices and one Arduino. This will connect each virtual device to each relay attached to the Arduino.

Dan this is amazing I can not stop checking all what your song and you have done. All the apps and devices work smoothly thanks a lot. I really enjoy it, and I want to implement each of them. I just have a small question, how do you use the virtual motion sensor since I can’t see a multiplexor for it. Actually, the only device that has more than one motion sensor is the alarm panel but as I understand that one was one of your first devices and didn’t aim to control devices separately. I have 2 motion sensor and I would like to use them as 2 different devices in the security dash board.
Thanks again!

Glad you got it working. Take a look at the ST_Anything_Alarm_ Panel set of files for an example of using multiple motion sensors.

HI Dan
I have a new question, I’m trying to use the digital sensor GY30 instead of the photo resistor,
However, I have some problems to integrate the code to yours. I am not sure if a new device is necesarty to be included in the library, plase let me know if thats the case.

Here the code (which is working well in another arduino)

#include <Wire.h>

int BH1750_address = 0x23; // i2c Addresse
byte buff[2];

void setup(){

Wire.begin();
BH1750_Init(BH1750_address);

delay(200);
Serial.begin(9600);
Serial.println(“Starte Beleuchtungsstaerkemessung - blog.simtronyx.de”);
}

void loop(){

float valf=0;

if(BH1750_Read(BH1750_address)==2){

valf=((buff[0]<<8)|buff[1])/1.2;

if(valf<0)Serial.print("> 65535");
else Serial.print((int)valf,DEC); 

Serial.println(" lx"); 

}
delay(1000);
}

void BH1750_Init(int address){

Wire.beginTransmission(address);
Wire.write(0x10); // 1 [lux] aufloesung
Wire.endTransmission();
}

byte BH1750_Read(int address){

byte i=0;
Wire.beginTransmission(address);
Wire.requestFrom(address, 2);
while(Wire.available()){
buff[i] = Wire.read();
i++;
}
Wire.endTransmission();
return i;
}

Hi Dan,

I am a newbee to both the Arduino experiment as well as SmartThings

I have created ( modified from other work ) an Arduino program running on a TKLCD board that is a Leonardo with an LCD attached. I have a SHT31 Temperature and Humidity sensor, and a K30 Carbon Dioxide sensor, both working from the I2C port of the Leonardo. I have the Arduino SmartThings shield, mounted on a Uno Proto board, and hard wired via a 4 pin connector to the Hardware serial port of the Leonardo ( serial1), as well as connected to D6, and a connection to the Reset… Also a LED driven by a NPN transistor on D5.

Interesting to note if you look at the Arduino Smart Things Shield, the reset from the shield pulls the reset low on the Leonardo, but not visa versa. No issue though.

The attached Arduino programs runs OK. I have a Smartthings Hub running, paired to an Android smart phone. I am receiving notifications and can see the three strings that are being sent from the Arduino, to the Smartthings shield, then via the hub to my phone.

My issue is the Device Handler and the Smart App for the phone. I am confused that when others publish a project they include an .ino code and groovy code. Is the Groovy code a Device handler or a Smart App?

Groovy Code
// ------------------------------------------------------------------------------------------------------
// 051716 SHT31_K30 Groovy Code for Smart Things Arduino Shield
// with Adafruit SHT31 Temperature and Humidity sensor with K30 CO2 sensor

metadata {
// Automatically generated. Make future change here.
definition (name: “Will’s Garage”, namespace: “Will_W”, author: “Ben Wolodko”) {
capability "Refresh"
capability "Polling"
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Carbon Dioxide Measurement"
capability “Sensor”

    fingerprint profileId: "0104", deviceId: "0138", inClusters: "0000"

}

// Simulator metadata
simulator {
// status messages
// status “ping”: “catchall: 0104 0000 01 01 0040 00 6A67 00 00 0000 0A 00 0A70696E67”
//status “hello”: “catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A48656c6c6f20576f726c6421”
}

// UI tile definitions
tiles {

valueTile("roomTemp", "device.roomTemp", width: 1, height: 1, inactiveLabel: false) {
    state("temperature", label: 'F1_Room ${currentValue}°C', unit:"C", backgroundColors: [
            [value: 31, color: "#153591"],
            [value: 44, color: "#1e9cbb"],
            [value: 59, color: "#90d2a7"],
            [value: 74, color: "#44b621"],
            [value: 84, color: "#f1d801"],
            [value: 95, color: "#d04e00"],
            [value: 96, color: "#bc2323"]
        ]
    )
}

valueTile("humidity_F1", "device.humidity_F1", width: 1, height: 1, inactiveLabel: false) {
    state "humidity", label:'F1_Room\n${currentValue}% humidity', unit:""
}

valueTile("cO2_F1", "device.cO2_F1", width: 1, height: 1, inactiveLabel: false) {
    state "cO2", label:'F1_CO2\n${currentValue}PPM cO2', unit:""
}


standardTile("refresh", "device.poll") {
    state "default", label:'Refresh', action:"device.poll()", icon:"st.secondary.refresh"
}

main (["roomTemp", "humidity_F1", "cO2_F1"])
details(["roomTemp", "humidity_F1", "cO2_F1"])

}
}

Map parse(String description) {

def value = zigbee.parse(description)?.text

log.debug “Parsing ‘${description}’”
// Not super interested in ping, can we just move on?
if (value == “ping” || value == " ")
{
return
}

def linkText = getLinkText(device)
def descriptionText = getDescriptionText(description, linkText, value)
def handlerName = value
def isStateChange = value != "ping"
def displayed = value && isStateChange

def result = [
value: value,
handlerName: handlerName,
linkText: linkText,
descriptionText: descriptionText,
isStateChange: isStateChange,
displayed: displayed
]

log.debug result.value

if (value in ["!on","!off"])
{
result.name = "switch"
result.value = value[1…-1]
// log.debug result.value
// } else if (value && value[0] == “%”) {
// result.name = “level”
// result.value = value[1…-1]

} else if (value && value[0] == "A") {
result.name = "humidity_F1";
result.value = value[1..-1];
result.unit = "%"

// log.debug ‘humidity_F1’
// log.debug result.value

} else if (value && value[0] == “B”) {
result.name = “RoomTemp”;
result.value = value[1…-1];
result.unit = “C”
// log.debug ‘roomTemp’
// log.debug result.value

} else if (value && value[0] == “C”) {
result.name = “cO2_F1”;
result.value = value[1…-1];
result.unit = “%”
// log.debug ‘cO2_F1’
// log.debug result.value

} else {
result.name = null;
log.debug  result.value

}
// if ( (value && value[0] == “%”) )
// {
// result.unit = “%”

// }
log.debug result.descriptionText
createEvent(name: result.name, value: result.value)

}

def poll() {
zigbee.smartShield(text: “poll”).format()
}

Arduino code
//-------------------------------------------------------------------------------------------------------------------------------------
//*****************************************************************************
/// @file
/// @brief
/// Arduino SmartThings Shield LED Example with Network Status
/// @note
///
/// TKLCD with Leonardo CPU and attached LCD
/// SHT31 Humidity and Temperature sensor on I2C address: 0x44
/// K30 CO2 Sensor on I2C Address: 0x68
/// Hard wired the Arduino Smart Things Shield to TKLCD Hardware Serial Port
/// Sketch uses 21,634 bytes (75%) of program storage space. Maximum is 28,672 bytes.
/// Global variables use 1,301 bytes (44%) of dynamic memory, leaving 1,259 bytes for
/// local variables. Maximum is 2,560 bytes.
///
///
//*****************************************************************************
#include <SoftwareSerial.h> //TODO need to set due to some weird wire language linker, should we absorb this whole library into smartthings
#include <SmartThings.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include <TKLCD.h>
#include “Adafruit_SHT31.h”
#include <avr/pgmspace.h>
Adafruit_SHT31 sht31 = Adafruit_SHT31();

TKLCD_Local lcd = TKLCD_Local(); // when programming a TKLCD module itself

//*****************************************************************************
// 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
//*****************************************************************************
#define PIN_LED 5
#define PIN_THING_RX 0 // RX for Leonardo on TKLCD
#define PIN_THING_TX 1 // TX for Leonardo on TKLCD

//*****************************************************************************
// 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
SmartThings smartthing(PIN_THING_RX, PIN_THING_TX, messageCallout); // constructor

bool isDebugEnabled; // enable or disable debug in this example
int stateLED; // state to track last set value of LED
int stateNetwork; // state of the network
int co2Addr = 0x68;
int ti=0;
int hi=0;
String humiditySHT31Message;
String temperatureSHT31Message;
String k30CO2Message;
String strti;
String strhi;
String strco2;

//*****************************************************************************
// 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 on()
{
stateLED = 1; // save state as 1 (on)
digitalWrite(PIN_LED, HIGH); // turn LED on
smartthing.shieldSetLED(0, 0, 2);
smartthing.send(“on”); // send message to cloud
}

//*****************************************************************************
void off()
{
stateLED = 0; // set state to 0 (off)
digitalWrite(PIN_LED, LOW); // turn LED off
smartthing.shieldSetLED(0, 0, 0);
smartthing.send(“off”); // send message to cloud
}

//*****************************************************************************
void setNetworkStateLED()
{
SmartThingsNetworkState_t tempState = smartthing.shieldGetLastNetworkState();
if (tempState != stateNetwork)
{
switch (tempState)
{
case STATE_NO_NETWORK:
if (isDebugEnabled) Serial.println(“NO_NETWORK”);
smartthing.shieldSetLED(2, 0, 0); // red
break;
case STATE_JOINING:
if (isDebugEnabled) Serial.println(“JOINING”);
smartthing.shieldSetLED(2, 0, 0); // red
break;
case STATE_JOINED:
if (isDebugEnabled) Serial.println(“JOINED”);
smartthing.shieldSetLED(0, 0, 0); // off
break;
case STATE_JOINED_NOPARENT:
if (isDebugEnabled) Serial.println(“JOINED_NOPARENT”);
smartthing.shieldSetLED(2, 0, 2); // purple
break;
case STATE_LEAVING:
if (isDebugEnabled) Serial.println(“LEAVING”);
smartthing.shieldSetLED(2, 0, 0); // red
break;
default:
case STATE_UNKNOWN:
if (isDebugEnabled) Serial.println(“UNKNOWN”);
smartthing.shieldSetLED(0, 2, 0); // green
break;
}
stateNetwork = tempState;
}
}

//*****************************************************************************
// 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() {

int co2_value = 467;
// setup default state of global variables
isDebugEnabled = true;
stateLED = 0; // matches state of hardware pin set below
stateNetwork = STATE_JOINED; // set to joined to keep state off if off

// setup hardware pins
pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output
digitalWrite(PIN_LED, LOW); // set value to LOW (off) to match stateLED=0

lcd.begin();
lcd.clear();
lcd.setCursor(0, 0);
Wire.begin ();
sht31.begin(0x44); // Set to 0x45 for alternate i2c addr

if (isDebugEnabled)
{ // setup debug serial port
Serial.begin(9600); // setup serial with a baud rate of 9600
// while (!Serial); // will pause Leonardo, etc until one clicks to open the serial console
// also will not proceed with stand alone LCD without plugging in USB, so cannot use
// for stand alone operation

Serial.println("setup..");  // print out 'setup..' on start

}
}

///////////////////////////////////////////////////////////////////
// Function : int readCO2()
// Returns : CO2 Value upon success, 0 upon checksum failure
// Assumes : - Wire library has been imported successfully.
// - LED is connected to IO pin D5
// - CO2 sensor address is defined in co2_addr
///////////////////////////////////////////////////////////////////
int readCO2()
{
int co2_value = 0;
// We will store the CO2 value inside this variable.
digitalWrite(5, HIGH);
// On most Arduino platforms this pin is used as an indicator light.
//////////////////////////
/* Begin Write Sequence */
//////////////////////////
Wire.beginTransmission(co2Addr);
Wire.write(0x22);
Wire.write(0x00);
Wire.write(0x08);
Wire.write(0x2A);

Wire.endTransmission();
/////////////////////////
/* End Write Sequence. /
/////////////////////////
/

We wait 10ms for the sensor to process our command.
The sensors’s primary duties are to accurately
measure CO2 values. Waiting 10ms will ensure the
data is properly written to RAM
/
delay(10);
/////////////////////////
/
Begin Read Sequence /
/////////////////////////
/

Since we requested 2 bytes from the sensor we must
read in 4 bytes. This includes the payload, checksum,
and command status byte.
/
Wire.requestFrom(co2Addr, 4);
byte i = 0;
byte buffer[4] = {0, 0, 0, 0};
/

Wire.available() is not nessessary. Implementation is obscure but we leave
it in here for portability and to future proof our code
/
while (Wire.available())
{
buffer[i] = Wire.read();
i++;
}
///////////////////////
/
End Read Sequence /
///////////////////////
/

Using some bitwise manipulation we will shift our buffer
into an integer for general consumption
*/
co2_value = 0;
co2_value |= buffer[1] & 0xFF;
co2_value = co2_value << 8;
co2_value |= buffer[2] & 0xFF;
byte sum = 0; //Checksum Byte
sum = buffer[0] + buffer[1] + buffer[2]; //Byte addition utilizes overflow

if (sum == buffer[3])
{
// Success!
digitalWrite(5, LOW);
return co2_value;
}
else
{
// Failure!
/*
Checksum failure can be due to a number of factors,
fuzzy electrons, sensor busy, etc.
*/
digitalWrite(5, LOW);
return 0;
}
}

//*****************************************************************************
void loop() {
float t = sht31.readTemperature();
float h = sht31.readHumidity();

ti=int(t);
hi=int(h);

String strti = String(t,1);
String strhi = String(hi);

// LCD print to second line of 16 x 2

lcd.setCursor(0, 1);
lcd.print("TEMP ");
lcd.print(ti);
lcd.print((char)223);
lcd.print(“C RH “);
lcd.print(hi);
lcd.print(”%”);

delay(200);

int co2Value = readCO2();

String strco2 = String(co2Value);

// if (co2Value > 0)
// {
// Serial.print("CO2 Value: ");
// Serial.println(co2Value);
// print to the First line of the LCD

lcd.setCursor(0, 0);

if (co2Value < 1000)
{
// if CO2 PPM count less than 1000 add an extra space
lcd.print(" CO2 “); // first 7 characters
}
else
{
// if CO2 PPM count greater than 1000 del an extra space
lcd.print(” CO2 “); // first 6 characters
}
lcd.print(co2Value);
lcd.print(” PPM ");
// }
// else
// {
// Serial.println(“Checksum failed / Communication failure”);
// }
// delay(2000);

// run smartthing logic
smartthing.run();
setNetworkStateLED();
Serial.println(" ");
Serial.println(“In the loop”);
// digitalWrite(PIN_LED, HIGH); // set value to LOW (off) to match stateLED=1
// delay(500);
// digitalWrite(PIN_LED, LOW); // set value to LOW (off) to match stateLED=0
// delay(3000);

Serial.println(F("Reporting data..."));
Serial.println("Messages to be delivered to SmartThings");

// Report Humidity from the SHT31

String humiditySHT31Message = "A";
humiditySHT31Message.concat(strhi);
smartthing.send(humiditySHT31Message);
Serial.println(humiditySHT31Message);

// Serial.println(strhi);

String temperatureSHT31Message = "B";
temperatureSHT31Message.concat(strti);
smartthing.send(temperatureSHT31Message);
Serial.println(temperatureSHT31Message);

// Serial.println(strti);

String k30CO2Message = "C";
k30CO2Message.concat(strco2);
smartthing.send(k30CO2Message);
Serial.println(k30CO2Message);

// Serial.println(strco2);

delay(10000);
}

//*****************************************************************************
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(“on”))
{
on();
}
else if (message.equals(“off”))
{
off();
}
}

//*****************************************************************************

I know that I am not using the ST-Anything code, partly because of the reminder of low dynamic memory
I also didnot see any sensors that used the I2C connections,

Your code abstraction is very elegant, but for a new guy, with really minimal C++ experience, the syntax was difficult to understand. Even what I presented here, is not fully understood,

I am just trying to solve a problem for our green house.

Thanks
Ben

The groovy code you posted above is a Device Handler. You will need to add it manually to your SmartThings web-based IDE under the “Device Handlers” and then publish it. Afterwards, go into your list of “Devices” in the IDE and edit the ThingShield device to use the new Device Handler you just published.

The way to think about it is

Physical Device
|
ST Hub
|
Device Handler (exposes capabilities/attributes of the physical device)
|
SmartApps (that use the data/event from the device handler)

Your phone’s SmartThings application simply is used to display/configure data from your Device Handlers, and to install/configure SmartApps that use data from the Device Handlers.

Hi Dan, thank you for your advice.

The system is working, but not without a lot of hair pulling. Using the Android phone I have, a Samsung Galaxy III, I cannot achieve a multiline Text display on the output of the phone. I have spent many hours trying to affect a newline trying \n and \r groovy operators, without success. The phone will also not allow the use of lowercase letters.

My question here , is there a groovy code that would detect that the power was shut off on the Arduino, and the shield is not transmitting values any more.

The current Groovy program, will display the last valid reding, and appears locked, if the power is removed from the Arduino.

Thanks

Ben

Ben,

The easiest way I could think to know the Arduino has stopped sending data would be have the Arduino send a timestamp text string every 30 seconds, or so. Display that string in a “Value Tile” via your Device Handler code so you will know the time of the last update by simply looking at it.

If you want to be notified that the Arduino is offline, you will need to write a SmartApp that can subscribe to the events from the Arduino Device Hander. The SmartApp would need to implement some sort of timeout logic (which can be problematic on the ST Cloud Platform since you will need to use a repeating timer - the new scheduler is much improved in this regard, so it may work well). If the timeout occurs before a regular EVENT comes in from the Arduino, you know it is offline and can then send a PUSH/TEXT notification to your phone.

FYI - My Arduino UNO R3 has been running my ST_Anything_Doors example for many months now, and it has never stopped sending data. It also properly recovers from a power loss, without user intervention. This doesn’t necessarily mean you should not implement your “power loss watchdog”, as your situation may be very different than mine (e.g. trying to run on batteries instead of an AC adapter.)

Hope this helps!

Dan

Hi Dan, thankyou for the reply

I assume a Watch dog timer is not possible in a Device handler?

Time stamp is a good thought, have to get RTC attached, could be using I2C
maybe from mills() or maybe just a toggle indicator that flips every time period, like a heart beat

Battery operation, in conjunction with an AC adapter , wired OR would also make things more relable
but thinking more of total power loss, both Arduino shield, and Hub ( hub has batteries in it, so do not know how long the hub would still be on when total power loss occurs)

If batteries were to power both, the hub and the Arduino shield ( my current system draws about 260 ma peak)
then one could just measure the Voltage from the AC adapter, and when that was down to 0 volts, then send some Text to a special valueTile.

Thanks Dan,

You are an inspiration …

1 Like