SmartThings Community

ESP8266 Smart Sprinkler System

smartapp_irrigation
dth_irrigation
requires_server
project_yard

(Dan) #41

I totally agree with your assessment. I think implementations like this Sprinkler project are ideal for people looking for more of a turn-key solution.

I do not know of many other systems with local processing that are as open as SmartThings. Vera Plus may be one option though, but I do not know if one is able to develop custom integrations to the level of what is possible in SmartThings.


(Rick) #42

Update here, I have been working on optimizing and fixing up the code to my liking.

I have fixed a few issues and added features.

There is a error in the dth that turns off the status for zone 3, just a mistypo called o3 vs on.

Fixed the ssdp upnp discovery I still can’t get it to show up automatically. But I’m not sure why it’s having issue with that.

Also I have added a password to the firmware update and reboot via the webpage.

I have cleaned up the device to match the 2x st layout.

Also it’s working great now.


#43

This is great. I just got my R8 in the mail. I am having the box printed and hope to get this setup this week.
I will be back


#44

Keep up the good work. In stead of using the built in schedule can I use webcore? The reason i ask is that i need to make a special schedule when blowing out my system for winter storage.


(Aaron Nienhuis) #45

Do you need to schedule your sprinkler controller while blowing out the system or do you just need to be able to manually turn on each valve for a period of time? You can manually set a time for each valve and turn them on and off without creating an automation schedule via the SmartApp. I guess I need a little more information on what you’re trying to accomplish. I’m not familiar enough with webcore to know whether it could be used.


#46

Can someone post the complete command line for esptool to upload the r8 binary to esp8266? I looked around and played quite a bit but esp8266 wouldnt create any access point.

Check attached picture for details and command line used… thanks in advance!


(Wes Treihaft) #47

Rickybobby, any chance at trying your new updated code? Been having the same issues you described.


(Rick) #48

@AlumaFX Sure I haven’t had a chance to update the code for the 8 Channel version which issues are you having ? Thanks!


(Wes Treihaft) #49

Exactly the same ones you were having above. I think I could update it to 8 channel. Still learning this language. Mind sharing? Winter is here so i have until spring before it needs to control my sprinklers again.


(Bdonchen) #50

Hi, not sure why but I can’t get this working. Any help is greatly appreciated.

I have the linknode r4, everything compiled properly and the SmartApp discovered and added the device. However, the device is not responding to any commands. When I click on start or any of the relay switches it says “sending” or “starting…” but nothing happens.

Am I missing something?

Thanks


(Rick) #51

@bdonchen I would have issues like that, after adding you need to wait about 5 min or so for st to auto change the device id to the MAC address of the linknode esp, one issue I noticed is if you try to re add the device to soon it will not change the MAC address I had to remove and wait about 24 hrs for st to do it automatically again.

The work around I found is just change the device id to the Mac manually in the IDE. It’s also a security built into st wifi devices can’t communicate with the hub unless that Mac is set. :slight_smile: also force closing the app after you enter the Mac is also a good idea.


(Bdonchen) #52

Force close/ restarting the app did the trick for me. You rock! Thank you so much.


(Rick) #53

/**

  • This is a start to porting the Arduino and SmartShield based
  • Irrigation Controllers to an ESP8266 based controller
  • Author: Aaron Nienhuis (aaron.nienhuis@gmail.com)
  • Date: 2017-01-11 handler modified by RICKYBobby minor fixes
  • Copyright 2017 Aaron Nienhuis
  • Irrigation Controller 4 Zones
  • This SmartThings Device Handler (Device Type) Code Works With the ESP8266 based Smart Sprinkler Irrigation Controllers also available at this site
  • Creates connected irrigation controller
  • ESP8266 port based on the extensive previous work of:
  • Author: Stan Dotson (stan@dotson.info) and Matthew Nichols (matt@nichols.name)
  • Portions of this work previously copyrighted by Stan Dotson and Matthew Nichols
  • Some code and concepts incorporated from other projects by:
  • Eric Maycock
  • 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.
    */

import groovy.json.JsonSlurper

// for the UI
preferences {

input("oneTimer", "text", title: "Zone One", description: "Zone One Time", required: false, defaultValue: "1")
input("twoTimer", "text", title: "Zone Two", description: "Zone Two Time", required: false, defaultValue: "1")
input("threeTimer", "text", title: "Zone Three", description: "Zone Three Time", required: false, defaultValue: "1")
input("fourTimer", "text", title: "Zone Four", description: "Zone Four Time", required: false, defaultValue: "1")

}

metadata {
definition (name: “Smart Sprinkler Controller 4 Zones”, version: “1.0.3”, author: "aaron.nienhuis@gmail.com", namespace: “anienhuis”) {

    capability "Switch"
    capability "Momentary"
    capability "Actuator"
	capability "Refresh"
	capability "Sensor"
    capability "Configuration"
    capability "Health Check"
    command "reboot"

    
    command "OnWithZoneTimes"
    command "RelayOn1"
    command "RelayOn1For"
    command "RelayOff1"
    command "RelayOn2"
    command "RelayOn2For"
    command "RelayOff2"
    command "RelayOn3"
    command "RelayOn3For"
    command "RelayOff3"
    command "RelayOn4"
    command "RelayOn4For"
    command "RelayOff4"
    command "update" 
    command "enablePump"
    command "disablePump"
    command "onPump"
    command "offPump"
    command "noEffect"
    command "skip"
    command "expedite"
    command "onHold"
    command "warning"
    attribute "effect", "string"
    
}

simulator {
      }

tiles(scale: 2) {
multiAttributeTile(name:"allZonesTile", type: "device.switch", width: 6, height: 4, decoration: "flat", canChangeIcon: true, canChangeBackground: true){
	tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
    attributeState "off", label: 'Start', action: "switch.on", icon: "st.Outdoor.outdoor12", backgroundColor: "#ffffff", nextState: "starting"
    attributeState "on", label: 'Running', action: "switch.off", icon: "st.Health & Wellness.health7", backgroundColor: "#00A0DC", nextState: "stopping"
    attributeState "starting", label:"Starting...", action:"switch.off", icon: "st.Health & Wellness.health7", backgroundColor: "#00A0DC"
    attributeState "stopping", label:'Stopping...', action: "switch.off", icon: "st.Health & Wellness.health7", backgroundColor: "#ff000f"
    attributeState "rainDelayed", label: 'Rain Delay', action: "switch.off", icon: "st.Weather.weather10", backgroundColor: "#fff000", nextState: "off"
    attributeState "warning", label: 'Issue',  icon: "st.Health & Wellness.health7", backgroundColor: "#ff000f", nextState: "off"
        }
        tileAttribute ("firmware", key: "SECONDARY_CONTROL") {
       		attributeState "firmware", label:'Firmware : ${currentValue}\r\n' 
        }
		tileAttribute ("ip", key: "SECONDARY_CONTROL") {
       		attributeState "ip", label:'\r\nIP : ${currentValue}' 
        }
	}   
    standardTile("zoneOneTile", "device.zoneOne", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
        state "off", label: 'One', action: "RelayOn1", icon: "st.Outdoor.outdoor12", backgroundColor: "#ffffff",nextState: "sending1"
        state "sending1", label: 'sending', action: "RelayOff1", icon: "st.Health & Wellness.health7", backgroundColor: "#cccccc"
        state "q", label: 'One', action: "RelayOff1",icon: "st.Outdoor.outdoor12", backgroundColor: "#c0a353", nextState: "sending1"
        state "on", label: 'One', action: "RelayOff1",icon: "st.Outdoor.outdoor12", backgroundColor: "#53a7c0", nextState: "sending1"
    }
    standardTile("zoneTwoTile", "device.zoneTwo", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
        state "off", label: 'Two', action: "RelayOn2", icon: "st.Outdoor.outdoor12", backgroundColor: "#ffffff", nextState: "sending2"
        state "sending2", label: 'sending', action: "RelayOff2", icon: "st.Health & Wellness.health7", backgroundColor: "#cccccc"
        state "q", label: 'Two', action: "RelayOff2",icon: "st.Outdoor.outdoor12", backgroundColor: "#c0a353", nextState: "sending2"
        state "on", label: 'Two', action: "RelayOff2",icon: "st.Outdoor.outdoor12", backgroundColor: "#53a7c0", nextState: "sending2"
    }
    standardTile("zoneThreeTile", "device.zoneThree", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
        state "off", label: 'Three', action: "RelayOn3", icon: "st.Outdoor.outdoor12", backgroundColor: "#ffffff", nextState: "sending3"
        state "sending3", label: 'sending', action: "RelayOff3", icon: "st.Health & Wellness.health7", backgroundColor: "#cccccc"
        state "q", label: 'Three', action: "RelayOff3",icon: "st.Outdoor.outdoor12", backgroundColor: "#c0a353", nextState: "sending3"
        state "on", label: 'Three', action: "RelayOff3",icon: "st.Outdoor.outdoor12", backgroundColor: "#53a7c0", nextState: "sending3"
    }
    standardTile("zoneFourTile", "device.zoneFour", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
        state "off", label: 'Four', action: "RelayOn4", icon: "st.Outdoor.outdoor12", backgroundColor: "#ffffff", nextState: "sending4"
        state "sending4", label: 'sending', action: "RelayOff4", icon: "st.Health & Wellness.health7", backgroundColor: "#cccccc"
        state "q", label: 'Four', action: "RelayOff4",icon: "st.Outdoor.outdoor12", backgroundColor: "#c0a353", nextState: "sending4"
        state "on", label: 'Four', action: "RelayOff4",icon: "st.Outdoor.outdoor12", backgroundColor: "#53a7c0", nextState: "sending4"
        state "havePump", label: 'Four', action: "disablePump", icon: "st.custom.buttons.subtract-icon", backgroundColor: "#ffffff"
    }
    standardTile("pumpTile", "device.pump", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
        state "noPump", label: 'Pump', action: "enablePump", icon: "st.custom.buttons.subtract-icon", backgroundColor: "#ffffff",nextState: "enablingPump"
     	state "offPump", label: 'Pump', action: "onPump", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState: "sendingPump"
       	state "enablingPump", label: 'sending', action: "disablePump", icon: "st.Health & Wellness.health7", backgroundColor: "#cccccc"
        state "disablingPump", label: 'sending', action: "disablePump", icon: "st.Health & Wellness.health7", backgroundColor: "#cccccc"
        state "onPump", label: 'Pump', action: "offPump",icon: "st.valves.water.open", backgroundColor: "#53a7c0", nextState: "sendingPump"
        state "sendingPump", label: 'sending', action: "offPump", icon: "st.Health & Wellness.health7", backgroundColor: "#cccccc"
    }
    	
    valueTile("refreshTile", "device.refresh", width: 2, height: 1, canChangeIcon: true, canChangeBackground: true, decoration: "flat") {
        state "ok", label: "Refresh", action: "update"
    }
    standardTile("scheduleEffect", "device.effect", decoration: "flat", width: 2, height: 2) {
        state("noEffect", label: "Normal", action: "skip", icon: "st.Office.office7", backgroundColor: "#ffffff")
        state("skip", label: "Skip 1X", action: "expedite", icon: "st.Office.office7", backgroundColor: "#c0a353")
        state("expedite", label: "Expedite", action: "onHold", icon: "st.Office.office7", backgroundColor: "#53a7c0")
        state("onHold", label: "Pause", action: "noEffect", icon: "st.Office.office7", backgroundColor: "#bc2323")
    }
	valueTile("reboot", "device.reboot", decoration: "flat", height: 1, width: 2, inactiveLabel: false) {
        state "default", label:"Reboot", action:"reboot"
    }
    valueTile("ip", "ip", width: 2, height: 1) {
		state "ip", label:'${currentValue}'
	}
    valueTile("firmware", "firmware", width: 2, height: 1) {
		state "firmware", label:'Firmware ${currentValue}'
	}
    
    main "allZonesTile"
    details(["allZonesTile","zoneOneTile","zoneTwoTile","zoneThreeTile","zoneFourTile","pumpTile","scheduleEffect","ip","reboot","refreshTile"])
}

}

// parse events into attributes to create events

// Original Parse from Irrigation Controller

def parse(String description) {

//log.debug "Parsing: ${description}"
def events = []
def descMap = parseDescriptionAsMap(description)
def body
def currentVal
def isDisplayed = true
def isPhysical = true
def name
def action
//log.debug "descMap: ${descMap}"

if (!state.mac || state.mac != descMap["mac"]) {
	log.debug "Mac address of device found ${descMap["mac"]}"
    updateDataValue("mac", descMap["mac"])
}

if (state.mac != null && state.dni != state.mac) state.dni = setDeviceNetworkId(state.mac)
if (!device.currentValue("ip") || (device.currentValue("ip") != getDataValue("ip"))) sendEvent(name: 'ip', value: getDataValue("ip"))

if (descMap["body"]) body = new String(descMap["body"].decodeBase64())

if (body && body != "") {

	if(body.startsWith("{") || body.startsWith("[")) {

		def slurper = new JsonSlurper()
		def jsonResult = slurper.parseText(body)
		           
        if (jsonResult.containsKey("relay")) {
        	jsonResult.relay.each {  rel ->
        	name = rel.key
            action = rel.value
        
            currentVal = device?.currentValue(name)
            //log.debug "Name $name Action $action Currentval $currentVal"
    		if (action != currentVal){
            	
                if (action == "on" ) {
        			isDisplayed = true
            		isPhysical = true
                 }
                 if (action == "off" || action == "q") {
        			isDisplayed = false
            		isPhysical = false
                 }
                 //log.debug "Executing $jsonResult.zoneOne"
            	 def result = createEvent(name: name, value: action, displayed: isDisplayed, isStateChange: true, isPhysical: isPhysical)
        		 sendEvent(result)
        	} else {
            	//log.debug "No change in value"
            }

		}
        }

        if (jsonResult.containsKey("pump")) {
        	def value = jsonResult.pump
			if (value == "onPump") {
				//send an event if there is a state change
    			if (device?.currentValue("pump") != "onPump") {
                	log.debug "parsing pump onPump"
    				sendEvent (name:"pump", value:"onPump", displayed: true, isStateChange: true, isPhysical: true)
                }
			}
            if (value == "offPump") {
				//send an event if there is a state change
    			if (device?.currentValue("pump") != "offPump") {
                	log.debug "parsing pump offPump"
    				sendEvent (name:"pump", value:"offPump", displayed: true, isStateChange: true, isPhysical: true)
                }
			}
            if (value == "pumpAdded") {
				//send an event if there is a state change
    			log.debug "parsing pump pumpAdded"
    			if (device?.currentValue("zoneFour") != "havePump" && device?.currentValue("pump") != "offPump") {
					sendEvent (name:"zoneFour", value:"havePump", displayed: true, isStateChange: true, isPhysical: true)
    				sendEvent (name:"pump", value:"offPump", displayed: true, isStateChange: true, isPhysical: true)
				}
			}
			if (value == "pumpRemoved") {
				//send event if there is a state change
    			if (device?.currentValue("pump") != "noPump") {
					sendEvent (name:"pump", value:"noPump", displayed: true, isStateChange: true, isPhysical: true)
				}
			}
		}
		if (jsonResult.containsKey("version")) {
        	//log.debug "firmware version: $jsonResult.version"
            if (device?.currentValue("firmware") != jsonResult.version) {
            	//log.debug "updating firmware version"
   				sendEvent(name:"firmware", value: jsonResult.version, displayed: false)
            }
		}


		if(anyZoneOn()) {
    		//manages the state of the overall system.  Overall state is "on" if any zone is on
    		//set displayed to false; does not need to be logged in mobile app
    		if(device?.currentValue("switch") != "on") {
    			sendEvent (name: "switch", value: "on", descriptionText: "Irrigation System Is On", displayed: false)  //displayed default is false to minimize logging
    		}
		} else if (device?.currentValue("switch") != "rainDelayed") {
    		if(device?.currentValue("switch") != "off") {
    			sendEvent (name: "switch", value: "off", descriptionText: "Irrigation System Is Off", displayed: false)  //displayed default is false to minimize logging
   			}
		}
	} else {
    	//log.debug "Response is not JSON: $body"
	}
}          

}

def anyZoneOn() {
if(device?.currentValue(“zoneOne”) in [“on”,“q”]) return true;
if(device?.currentValue(“zoneTwo”) in [“on”,“q”]) return true;
if(device?.currentValue(“zoneThree”) in [“on”,“q”]) return true;
if(device?.currentValue(“zoneFour”) in [“on”,“q”]) return true;

false;

}

// handle commands

def RelayOn1() {
log.info “Executing ‘on,1’“
getAction(”/command?command=on,1,${oneTimer}”)
}

def RelayOn1For(value) {
value = checkTime(value)
log.info “Executing ‘on,1,$value’”

getAction("/command?command=on,1,${value}")

}

def RelayOff1() {
log.info “Executing ‘off,1’”

getAction("/command?command=off,1")

}

def RelayOn2() {
log.info “Executing ‘on,2’”

getAction("/command?command=on,2,${twoTimer}")

}

def RelayOn2For(value) {
value = checkTime(value)
log.info “Executing ‘on,2,$value’”

getAction("/command?command=on,2,${value}")

}

def RelayOff2() {
log.info “Executing ‘off,2’”

getAction("/command?command=off,2")

}

def RelayOn3() {
log.info “Executing ‘on,3’”

getAction("/command?command=on,3,${threeTimer}")

}

def RelayOn3For(value) {
value = checkTime(value)
log.info “Executing ‘on,3,$value’”

getAction("/command?command=on,3,${value}")

}

def RelayOff3() {
log.info “Executing ‘off,3’”

getAction("/command?command=off,3")

}

def RelayOn4() {
log.info “Executing ‘on,4’”

getAction("/command?command=on,4,${fourTimer}")

}

def RelayOn4For(value) {
value = checkTime(value)
log.info “Executing ‘on,4,$value’”

getAction("/command?command=on,4,${value}")

}

def RelayOff4() {
log.info “Executing ‘off,4’”

getAction("/command?command=off,4")

}

def on() {
log.info “Executing ‘allOn’”

getAction("/command?command=allOn,${oneTimer ?: 0},${twoTimer ?: 0},${threeTimer ?: 0},${fourTimer ?: 0}")

}

def OnWithZoneTimes(value) {
log.info "Executing ‘allOn’ with zone times [$value]"
def evt = createEvent(name: “switch”, value: “starting”, displayed: true)
sendEvent(evt)

def zoneTimes = [:]
for(z in value.split(",")) {
	def parts = z.split(":")
    zoneTimes[parts[0].toInteger()] = parts[1]
    log.info("Zone ${parts[0].toInteger()} on for ${parts[1]} minutes")
}

getAction("/command?command=allOn,${checkTime(zoneTimes[1]) ?: 0},${checkTime(zoneTimes[2]) ?: 0},${checkTime(zoneTimes[3]) ?: 0},${checkTime(zoneTimes[4]) ?: 0},${checkTime(zoneTimes[5]) ?: 0},${checkTime(zoneTimes[6]) ?: 0},${checkTime(zoneTimes[7]) ?: 0},${checkTime(zoneTimes[8]) ?: 0}")

}

def off() {
log.info “Executing ‘allOff’”

getAction("/command?command=allOff")

}

def checkTime(t) {
def time = (t ?: 0).toInteger()
time > 60 ? 60 : time
}

def update() {
log.info “Executing refresh"
refresh()
//getAction(”/status")
}

def rainDelayed() {
log.info "rain delayed"
if(device.currentValue(“switch”) != “on”) {
sendEvent (name:“switch”, value:“rainDelayed”, displayed: true)
}
}

def warning() {
log.info "Warning: Programmed Irrigation Did Not Start"
if(device.currentValue(“switch”) != “on”) {
sendEvent (name:“switch”, value:“warning”, displayed: true)
}
}

def enablePump() {
log.info “Enabling Pump”

getAction("/command?command=pump,3")

}
def disablePump() {
log.info “Disabling Pump”

getAction("/command?command=pump,0")

}
def onPump() {
log.info “Turning On Pump”

getAction("/command?command=pump,2")
}

def offPump() {
log.info “Turning Off Pump”

getAction("/command?command=pump,1")
    }

def push() {
log.info “advance to next zone”

getAction("/command?command=advance")
}

// commands that over-ride the SmartApp

// skip one scheduled watering
def skip() {
def evt = createEvent(name: “effect”, value: “skip”, displayed: true)
log.info(“Sending: $evt”)
sendEvent(evt)
}
// over-ride rain delay and water even if it rains
def expedite() {
def evt = createEvent(name: “effect”, value: “expedite”, displayed: true)
log.info(“Sending: $evt”)
sendEvent(evt)
}

// schedule operates normally
def noEffect() {
def evt = createEvent(name: “effect”, value: “noEffect”, displayed: true)
log.info(“Sending: $evt”)
sendEvent(evt)
}

// turn schedule off indefinitely
def onHold() {
def evt = createEvent(name: “effect”, value: “onHold”, displayed: true)
log.info(“Sending: $evt”)
sendEvent(evt)
}

//Start of added functions

def reset() {
log.debug “reset()”
}

def refresh() {
log.debug “refresh()”

getAction("/status")

}

def ping() {
log.debug "ping()"
refresh()
}

def reboot() {
log.debug "reboot()"
def uri = "/reboot"
getAction(uri)
}

def sync(ip, port) {
def existingIp = getDataValue(“ip”)
def existingPort = getDataValue(“port”)
if (ip && ip != existingIp) {
updateDataValue(“ip”, ip)
sendEvent(name: ‘ip’, value: ip)
}
if (port && port != existingPort) {
updateDataValue(“port”, port)
}
}
private encodeCredentials(username, password){
def userpassascii = "${username}:${password}"
def userpass = "Basic " + userpassascii.encodeAsBase64().toString()
return userpass
}

private getAction(uri){
updateDNI()
def userpass
log.debug uri
if(password != null && password != “”)
userpass = encodeCredentials(“admin”, password)

def headers = getHeader(userpass)

def hubAction = new physicalgraph.device.HubAction(
method: “GET”,
path: uri,
headers: headers
)
return hubAction
}

private postAction(uri, data){
updateDNI()

def userpass

if(password != null && password != “”)
userpass = encodeCredentials(“admin”, password)

def headers = getHeader(userpass)

def hubAction = new physicalgraph.device.HubAction(
method: “POST”,
path: uri,
headers: headers,
body: data
)
return hubAction
}

private setDeviceNetworkId(ip, port = null){
def myDNI
if (port == null) {
myDNI = ip
} else {
def iphex = convertIPtoHex(ip)
def porthex = convertPortToHex(port)

    myDNI = "$iphex:$porthex"
}
log.debug "Device Network Id set to ${myDNI}"
return myDNI

}

private updateDNI() {
if (state.dni != null && state.dni != “” && device.deviceNetworkId != state.dni) {
device.deviceNetworkId = state.dni
}
}

private getHostAddress() {
if(getDeviceDataByName(“ip”) && getDeviceDataByName(“port”)){
return “${getDeviceDataByName(“ip”)}:${getDeviceDataByName(“port”)}”
}else{
return “${ip}:80”
}
}

private String convertIPtoHex(ipAddress) {
String hex = ipAddress.tokenize( ‘.’ ).collect { String.format( ‘%02x’, it.toInteger() ) }.join()
return hex
}

private String convertPortToHex(port) {
String hexport = port.toString().format( ‘%04x’, port.toInteger() )
return hexport
}

def parseDescriptionAsMap(description) {
description.split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}

private getHeader(userpass = null){
def headers = [:]
headers.put(“Host”, getHostAddress())
headers.put(“Content-Type”, “application/x-www-form-urlencoded”)
if (userpass != null)
headers.put(“Authorization”, userpass)
return headers
}

def toAscii(s){
StringBuilder sb = new StringBuilder();
String ascString = null;
long asciiInt;
for (int i = 0; i < s.length(); i++){
sb.append((int)s.charAt(i));
sb.append("|");
char c = s.charAt(i);
}
ascString = sb.toString();
asciiInt = Long.parseLong(ascString);
return asciiInt;
}

def setProgram(value, program){
state.“program${program}” = value
}

def hex2int(value){
return Integer.parseInt(value, 10)
}

def update_needed_settings()
{
def cmds = []

def isUpdateNeeded = "NO"

cmds << getAction("/config?hubIp=${device.hub.getDataValue("localIP")}&hubPort=${device.hub.getDataValue("localSrvPortTCP")}")
    
sendEvent(name:"needUpdate", value: isUpdateNeeded, displayed:false, isStateChange: true)
return cmds

}

def installed() {
log.debug "installed()"
configure()
}

def configure() {
log.debug "configure()"
def cmds = []
cmds = update_needed_settings()
if (cmds != []) response(cmds)
}

def updated()
{
log.debug "updated()"
def cmds = []
cmds = update_needed_settings()
sendEvent(name: “checkInterval”, value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: “lan”, hubHardwareId: device.hub.hardwareID])
if (cmds != []) response(cmds)
}


(Dan) #54

Pro Tip - When sharing code, please highlight it and click the Preformatted Text format button (looks like < / > in the edit window menu bar.) Even better, just paste a link to your code in Github.


(Rick) #55

@ogiewon thanks yeah I thought it might not come across & I posted via my phone. I will go ahead and post a link soon. :slight_smile: I’m working on another project atm. Thanks!


(s) #56

I am late to the game, but this project has me excited. I have the Linknode R4 (I only have 3 zones) and I was able to flash the firmware, connected it to my Wifi, and I am able to discover it but when I go to save it, it just hangs at that screen. Any information of what I might be doing wrong?


(s) #57

I am getting so close to the finish line. Everything is up and running now. I have tested each relay with a time to run and they do click on.

When I try to run a station individually without setting up a time, the relays do not click on. I have tried the fix above but still not having any luck. Anybody able to help me out?


(Aaron Nienhuis) #58

To run individual stations, you need to make sure you go into Settings on the Device (gear in the upper right corner) and set the run times for the individual stations. The SmartApp works separately to run timed schedules. Individual zone time are set within the device settings.


(s) #59

Yeah I missed that part in the instructions, found it late last night. Got it all up and working. Now to wire it in place. I am so excited, I really appreciate the work you have done on this.

Now I’m looking for a way to do the same thing for the garage door using the esp8266, but I’m not a code person.


(Al) #62

Would someone please post where/how to get the correct dependent library .h files. I did not see instructions here. The files do not seem to be included in the default IDE install and some not part of the released library. I found stopAll() in libraries\ESP8266WiFi\src\WIFIUdp.h but not in libraries\WiFi\src\WIFIUdp.h; Not sure why I have two so I renamed the latter .h_ still get error:

Arduino: 1.8.5 (Windows 10), Board: “Generic ESP8266 Module, 80 MHz, 40MHz, DIO, 115200, 512K (64K SPIFFS), ck, Disabled, None”

In file included from C:\Program Files (x86)\Arduino\libraries\Adafruit_Circuit_Playground/Adafruit_CircuitPlayground.h:3:0,

             from smart_sprinkler-master\ESP8266\ESP8266_8_Zone_Irrigation_Controller\ESP8266_8_Zone_Irrigation_Controller.ino:1:

C:\Program Files (x86)\Arduino\libraries\Adafruit_Circuit_Playground/Adafruit_Circuit_Playground.h:98:3: error: ‘Adafruit_CPlay_FreeTouch’ does not name a type

Adafruit_CPlay_FreeTouch cap[7];

^

In file included from C:\Users\aldude\Downloads\smart_sprinkler-master\smart_sprinkler-master\ESP8266\ESP8266_8_Zone_Irrigation_Controller\ESP8266_8_Zone_Irrigation_Controller.ino:69:0:

C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266mDNS/ESP8266mDNS.h:117:3: error: ‘WiFiEventHandler’ does not name a type

WiFiEventHandler _disconnectedHandler;

^

C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266mDNS/ESP8266mDNS.h:118:3: error: ‘WiFiEventHandler’ does not name a type

WiFiEventHandler _gotIPHandler;

^

Multiple libraries were found for "SPI.h"
Used: C:\Users\Al\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\SPI
Not used: C:\Program Files (x86)\Arduino\libraries\SPI
Multiple libraries were found for "WiFiUdp.h"
Used: C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi_Link
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi101
Not used: C:\Program Files (x86)\Arduino\libraries\ESP8266WiFi
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi_Link
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi101
Not used: C:\Program Files (x86)\Arduino\libraries\ESP8266WiFi
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi_Link
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi101
Not used: C:\Program Files (x86)\Arduino\libraries\ESP8266WiFi
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi_Link
Not used: C:\Program Files (x86)\Arduino\libraries\WiFi101
Not used: C:\Program Files (x86)\Arduino\libraries\ESP8266WiFi
Multiple libraries were found for "DNSServer.h"
Used: C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\DNSServer
Not used: C:\Program Files (x86)\Arduino\libraries\DNSServer
Multiple libraries were found for "ESP8266WebServer.h"
Used: C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WebServer
Not used: C:\Program Files (x86)\Arduino\libraries\ESP8266WebServer
Multiple libraries were found for "ESP8266mDNS.h"
Used: C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266mDNS
Not used: C:\Program Files (x86)\Arduino\libraries\ESP8266mDNS
Multiple libraries were found for "ESP8266SSDP.h"
Used: C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266SSDP
Not used: C:\Program Files (x86)\Arduino\libraries\ESP8266SSDP
Multiple libraries were found for "Wire.h"
Used: C:\Users\aldude\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\Wire
Not used: C:\Program Files (x86)\Arduino\libraries\Wire
exit status 1
Error compiling for board Generic ESP8266 Module.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.