The Smart Socket is a Sonoff S20 (or successor) plug-in version of the wired Smart Switch - they both use the same script, the only difference is in the usage.
The Smart Socket uses the integral gpio0 push-button to differentiate between short or long button presses, whereas the Smart Switch is able to use gpio0 for a bi-state lever switch, which therefore makes On durations irrelevant (therefore no ability for short or long button-press timings).
The default script offers On/Off and Toggle, plus Delayed Cycle On/Off for a specified Duration, or Scheduled On/Off, or Thermostat control, or Sensor trigger.
The integrated hardware button provides a physical local Toggle, plus the device can be remotely controlled via web page or UDP.
The button surround allows an internal blue LED to show when the relay is On.
Similarly a green user LED shows any pending countdown timers.
A short button press toggles the relay (blue LED), whereas a long button press blinks out the IP address on the green LED.
This Smart Socket demo video will give an idea of what it can do and how to use it.
Refer to the Smart Switch project for a more detailed explanation of what this 'Smart' script does, and how it does it.
You may also want to refer to the TX RX Hack, which conveniently and safely offers 2 additional user gpio's for sensors etc,
It also offers a safe means of serial flashing with the device removed from the Mains, and without needing to dismantle it.
The Smart Socket can be used 'standalone' by itself, or can interact with other EasyNet devices if wished.
So for example a Smart Switch might control one or more Smart Sockets (all using exactly the same script with identical network configuration).
EasyNet is entirely optional and transparent though, so simply ignore it if not needed.
An EasyNet device can be addressed by its Nodename, or by partial Groupname, or by its IP address, or "All".
If no meaningfull nodename is assigned (because you forgot or couldn't be bothered at the time), the script will assign itself a unique nodename.
So consider a scenario where several EasyNet devices with the same default scripts all received arbitrary DHCP addresses from the router and you don't know anything about any of it !!
It is actually quite simple to find out what's what...
All EasyNet nodes will respond to the name "ALL", and all nodes will respond to "Reply", "Blink", and "BlinkIP" UDP instructions.
So sending "ALL REPLY" from the UDP console will cause all nodes to reply with their Nodename and IP address.
Once you know the nodenames you can send each in turn a "Blink" instruction to show their physical location by blinking their LED.
They already replied with their Nodename and IP address anyway, but sending "BlinkIP" to a Nodename would cause it to locally blink out its IP address on its LED.
The only reason for knowing device IP addresses is to connect to them from a browser for user management, because they are not needed for device interactions.
Note: Developed on 1.39 beta 1, and does not work on version 1.39 beta 2 because of a firmware bug, but should hopefully be fixed in the next release.
Basic:
title$ = "EasyNet Smart Switch/Socket - by Electroguard - developed on Annex 1.39 beta 1"
nodename$ = "" 'Assign a unique node name of your choice (if you forget, it will be called "Node" + its node IP)
groupname$ = "Sonoff\Smart\Switch\Socket\Relay" 'concatenated group names are searched for a partial match
localIP$ = WORD$(IP$,1)
netIP$ = WORD$(localIP$,1,".") + "." + WORD$(localIP$,2,".") + "." + WORD$(localIP$,3,".") + "."
nodeIP$ = WORD$(localIP$,4,".")
udpport = 5001 'change to suit your own preference, but don't forget to do the same for all nodes
if nodename$ = "" then nodename$ = "Node" + nodeIP$
showsettings = 0
showtitle = 1
showID = 0 '=1 to show local identity info
showbuttons = 1 '=1 to show onscreen system buttons
showclock = 0 '=1 to show clock and schedule options
showscheduled = 0 '=1 to show scheduled alarm On and Off times
showcycled = 0 '=1 to show cycleOn and cycleOff options
showswmodes = 0 '=1 to show harware button and switch mode checkboxes
showtools = 0 '=1 to show onscreen system buttons
showtherm = 0 '=1 to show temperature display
showstat = 0 '=1 to enable thermostat options
'filename$ = word$(BAS.FILENAME$,1,".") + ".ini" 'Un-comment this line to save settings to 'this scriptname'.inifilename$ = "/program/smartswitch.ini" 'Uncomment this line to save to a specfied filefontpath$ = "/font/" 'path to optional font filefontfile$ = "dig7monoitalic.ttf" 'filename.ext of optional font fileinstructionslist$ = "Reply Report BlinkIP Blink Save Load " 'List of Subdir branches available as remote triggersinstructionslist$ = instructionslist$ + "Relay1On Relay1Off Toggle1 Cycle1On Cycle1Off" 'List of Subdir branches available as remote triggerssetpoint = 22 'thermostat setpointstatlist$ = "fan,heater" statmode$ = "fan" 'fan switches relay on if temp above setpoint, heater switches relay on if temp below setpoint.dallaspin = 1 'Dallas 1-wire temperature sensor pintemp$ = str$(val(tempr$(dallaspin,1)),"%2.1f")newtemp$ = ""enablestat = 0 '=1 to enable thermostat switchingenablescheduledOn = 0 '=1 to enable scheduled On timeenablescheduledOff = 0 '=1 to enable scheduled Off timeontime$ = "8:01"offtime$ = "8:02"unitslist$ = "secs, mins, hours, days"secs = 1: mins = secs * 60: hours = mins * 60: days = hours * 24enabledelayon = 0 '=1 enable cycleOn delayondelay = 7 'cycleOn delayondelunits$ = "days"ondelaycountdown = -1enabletimedon = 1 '=1 enable cycleOn durationonduration = 1 'cycleOn durationondurunits$ = "mins"ondurationcountdown = -1enabledelayoff = 1 '=1 enable cycleOff delayoffdelay = 10 'cycleOff durationoffdelunits$ = "secs"offdelaycountdown = -1enabletimedoff = 1 '=1 enable cycleOff durationoffduration = 30 'cycleOff durationoffdurationcountdown = -1offdurunits$ = "secs"instruction$ = "" 'variable to hold incoming instructionRXmsg$ = "" 'variable to hold incoming messagedata$ = "" 'variable to hold any incoming data which follows the instructionretryq$ = "" 'variable to hold all unexpired messages still waiting to be acknowledgedqdelimiter$ = "|" 'separates messages in the retryqtime2live = 30 'sent-message unacknowledged lifetime in secondsled1pin = 13: led1off = 1: pin.mode led1pin, output: pin(led1pin) = led1offrelay1pin = 12: relay1noff = 0: pin.mode relay1pin, output: pin(relay1pin) = relay1noff 'using active high qpio12 for relay1switchpin = 3: switchoff = 1: pin.mode switchpin, input, pullup 'switch normally high active lowswitchmode = 1 '1=bi-state lever switch, 0=momentary press to toggle buttoninterrupt switchpin, switchedbuttonpin = 0: pin.mode buttonpin, input, pullup 'using active low gpio0 buttonbuttonmode = 0 '1=bi-state lever switch, 0=momentary press to toggle buttoninterrupt buttonpin, pressedstart=0: stop=0 'used by button-pressed subroutine to differentiate between short and long pressesdebounce = 100longpress=3000 'longpress set high at 3 secs to minimise accidental triggering of blinkIPledstat$ = "green"blinks = 10 'blink default number of blinks, can be over-ridden by sending "nodename blink number_of_blinks"'gosub load 'ini file mechanism is not fully implementedgosub paintonhtmlchange changedonhtmlreload painttimer0 1000, ticker timer1 1000, Retry 'periodic timer to keep resending unACKed msgs until they expire udp.begin(udpport)onudp udpRXwlog "Started: " + time$ + " on " + date$waitpaint:clsautorefresh 1000a$ = a$ + |<br><div id='message' data-var='clicked' onclickx='cmdButton(this)' style='display: table; margin-right:auto;margin-left:auto;text-align:center;'>|if showtitle = 1 then a$ = a$ + title$ + "<br><br>"if showID = 1 then a$ = a$ + |<table align='center'><tr><td>| a$ = a$ + |Node name:</td><td>| + textbox$(nodename$,"tbname") + |</td></tr><tr><td>| a$ = a$ + cssid$("tbname", "color:Darkcyan;font-size:1.2em;width:150px;") a$ = a$ + |local IP:</td><td>| + localIP$ + |</td></tr><tr><td>| a$ = a$ + |UDP port:</td><td>| + textbox$(udpport,"tb40") + |</td></tr></td></tr></table><br><br>|endifif showbuttons = 1 then a$ = a$ + button$("Instant On",relay1on) + string$(9," ") + button$("Toggle", toggle1, "butled") + string$(9," ") + button$("Instant Off",relay1off) + |<br><br>| a$ = a$ + cssid$("butled", "height:3em; font-size:1.5em; border-radius:.4em; padding:.5em; color:white; background:" + ledstat$ + ";")endifif showclock = 1 then a$ = a$ + |<div style='display: table; margin-right:auto;margin-left:auto;text-align:center;borderx:1px solid gray;'>| a$ = a$ + |<style> @font-face { font-family: myfont; src: url('| + fontpath$ + fontfile$ + |');} </style><br>| a$ = a$ + |<div id='clock' style='font-family:myfont;background:lightcyan;color:dimgray;font-size:2.9em;border:1px solid gray;text-align:center;| a$ = a$ + |display: table; margin-right:auto;margin-left:auto;padding-left:.4em;padding-right:.4em;'>| + time$ + |</div><br>|endifif showscheduled = 1 then a$ = a$ + |<div style='display: table; margin-right:auto;margin-left:auto;text-align:center;borderx:1px solid gray;'>| a$ = a$ + checkbox$(enablescheduledon) + " " + |On Time:| + textbox$(ontime$,"tb40") + string$(9," ") a$ = a$ + checkbox$(enablescheduledoff) + " " + |Off Time:</td><td>| + textbox$(offtime$,"tb40") + |<br>| a$ = a$ + |</div>|endifhtml a$pause 200a$ = ""if (showtherm = 1) or (showstat = 1) then a$ = a$ + |<div style='display: table; margin-right:auto;margin-left:auto;text-align:center;borderx:1px solid gray;'>| a$ = a$ + |<br><div id='temp' style='font-family: myfont;background:LightGoldenRodYellow ;color:dimgray;font-size:1.8em;text-align:center;border:1px solid gray;| a$ = a$ + |display: table; margin-right:auto;margin-left:auto;border-radius:3em;padding-left:.4em;padding-right:.3em;'>| + temp$ + "˚" + |</div>| a$ = a$ + "<br>" if showstat = 1 then a$ = a$ + button$(" < ", statdown) + " " + textbox$(setpoint,"tb30") + " " + button$(" > ", statup) + "<br>" a$ = a$ + checkbox$(enablestat) + listbox$(statmode$,statlist$,"tb80") + "<br><br>" endif a$ = a$ + |</div>|endifif showcycled = 1 then a$ = a$ + |<div style='display: table; margin-right:auto;margin-left:auto;text-align:center;borderx:1px solid gray;'>| a$ = a$ + |<table align='center'><tr><td>| a$ = a$ + button$("Controlled On ", cycle1on) + string$(9," ") + |</td><td>| + "On delay " + |</td><td>| a$ = a$ + " " + checkbox$(enabledelayon) + |</td><td>| + " " + textbox$(ondelay,"tb40") + |</td><td>| + listbox$(ondelunits$,unitslist$,"tb60") + |</td><td>| a$ = a$ + string$(9," ") + " On duration " + |</td><td>| + checkbox$(enabletimedon) + |</td><td>| + " " + textbox$(onduration,"tb40") + |</td><td>| + listbox$(ondurunits$,unitslist$,"tb60") + |</td></tr><br><tr><td>| a$ = a$ + button$("Controlled Off ", cycle1off) + string$(9," ") + |</td><td>| + "Off delay " + |</td><td>| a$ = a$ + " " + checkbox$(enabledelayoff) + |</td><td>| + " " + textbox$(offdelay,"tb40") + |</td><td>| + listbox$(offdelunits$,unitslist$,"tb60") + |</td><td>| a$ = a$ + string$(9," ") + " Off duration " + |</td><td>| + checkbox$(enabletimedoff) + |</td><td>| + " " + textbox$(offduration,"tb40") + |</td><td>| + listbox$(offdurunits$,unitslist$,"tb60") + |</td></tr></table><br>| a$ = a$ + |</div>|endifif showtools = 1 then a$ = a$ + |<div style='display: table; margin-right:auto;margin-left:auto;text-align:center;borderx:1px solid gray;'>| a$ = a$ + "<br>" + button$("Blink", blink) + " " + textbox$(blinks,"tb40") + string$(9," ") a$ = a$ + button$("Blink IP", blinkip) + string$(9," ") a$ = a$ + button$("Send", sendudp) + string$(9," ") a$ = a$ + button$("Save settings", save) + "<br>" a$ = a$ + |</div>|endifif showswmodes = 1 then a$ = a$ + "<br> gpio0 On/Off flip switch " + checkbox$(buttonmode) + " or momentary toggle button<br>" a$ = a$ + " gpio" + str$(switchpin) + " On/Off flip switch " + checkbox$(switchmode) + " or momentary toggle button<br>"endifa$ = a$ + "<br>ShowSettings:" + checkbox$(showsettings)if showsettings = 1 then a$=a$+", ShowTitle:"+checkbox$(showtitle)+", ShowID:"+checkbox$(showid)+", Buttons:"+checkbox$(showbuttons) a$=a$+", ShowClock:"+checkbox$(showclock)+", ShowScheduled:"+checkbox$(showscheduled) a$=a$+", ShowTherm:"+checkbox$(showtherm)+", ShowStat:"+checkbox$(showstat) a$=a$+", ShowCycled:"+checkbox$(showcycled)+", ShowTools:"+checkbox$(showtools)+", ShowSWmodes:"+checkbox$(showswmodes)+"<br>"+"<br>"endifa$ = a$ + cssid$("tb30", "width:30; text-align:center; color:teal; background:GhostWhite;")a$ = a$ + cssid$("tb40", "width:40; text-align:center; color:teal; background:GhostWhite;")a$ = a$ + cssid$("tb60", "width:60; text-align:center; color:teal; background:GhostWhite;")a$ = a$ + cssid$("tb80", "width:80; text-align:center; color:teal; background:GhostWhite;")a$ = a$ + |</div>|html a$a$ = ""returnsettings:if visibility$ = "Hide" then visibility$ = "Show" else visibility$ = "Hide"refreshreturnchanged:ch$ = HtmlEventVar$if instr(ch$,"show") = 1 then gosub paintif len(word$(ontime$,2,":")) = 1 then ontime$ = replace$(ontime$,":",":0")if len(word$(offtime$,2,":")) = 1 then offtime$ = replace$(offtime$,":",":0")returnticker:if showclock = 1 then jscall |_$('clock').innerHTML = "| + time$ + |"| ' updates the digital clock displayif (showtherm = 1) or (enablestat = 1) then newtemp$ = str$(val(tempr$(dallaspin,1)),"%2.1f") if (newtemp$ <> temp$) then temp$ = newtemp$ jscall |_$('temp').innerHTML = "| + temp$ + "˚" + |"| ' updates the temp display endifendifif enablestat = 1 then if val(temp$) < setpoint then 'turn heater on or fan off if (statmode$ = "heater") and (pin(relay1pin) = relay1noff) then if relay1noff = 0 then pin(relay1pin) = 1 else pin(relay1pin) = 0 html cssid$("butled", "background:red;") endif if (statmode$ = "fan") and (pin(relay1pin) <> relay1noff) then pin(relay1pin) = relay1noff html cssid$("butled", "background:green;") endif endif if (val(temp$) > setpoint) then if (statmode$ = "heater") and (pin(relay1pin) <> relay1noff) then pin(relay1pin) = relay1noff html cssid$("butled", "background:green;") endif if (statmode$ = "fan") and (pin(relay1pin) = relay1noff) then pin(relay1pin) = 1 - relay1noff html cssid$("butled", "background:red;") endif endifendifif (enablescheduledon = 1) and (pin(relay1pin) = relay1noff) then if (val(word$(ontime$,1,":")) = val(word$(time$,1,":"))) and (val(word$(ontime$,2,":")) = val(word$(time$,2,":"))) then gosub relay1onendifif (enablescheduledoff = 1) and (pin(relay1pin) <> relay1noff) then if (val(word$(offtime$,1,":")) = val(word$(time$,1,":"))) and (val(word$(offtime$,2,":")) = val(word$(time$,2,":"))) then gosub relay1offendifif ondelaycountdown >= 0 then if pin(led1pin) = 0 then pin(led1pin) = 1 else pin(led1pin) = 0 if ondelaycountdown > 0 then ondelaycountdown = ondelaycountdown -1 else ondelaycountdown = -1 gosub relay1on COMMAND "m=" + ondurunits$ if enabletimedon = 1 then ondurationcountdown = onduration * m endifendifif ondurationcountdown >= 0 then if pin(led1pin) = 0 then pin(led1pin) = 1 else pin(led1pin) = 0 if ondurationcountdown > 0 then ondurationcountdown = ondurationcountdown -1 else ondurationcountdown = -1 gosub relay1off endifendifif offdelaycountdown >= 0 then if pin(led1pin) = 0 then pin(led1pin) = 1 else pin(led1pin) = 0 if offdelaycountdown > 0 then offdelaycountdown = offdelaycountdown -1 else offdelaycountdown = -1 gosub relay1off COMMAND "m=" + offdurunits$ if enabletimedoff = 1 then offdurationcountdown = offduration * m endifendifif offdurationcountdown >= 0 then if pin(led1pin) = 0 then pin(led1pin) = 1 else pin(led1pin) = 0 if offdurationcountdown > 0 then offdurationcountdown = offdurationcountdown -1 else offdurationcountdown = -1 gosub relay1on endifendifreturnstatup:setpoint = setpoint + 1newtemp$ = ""refreshreturnstatdown:setpoint = setpoint - 1if setpoint < 0 then setpoint = 0newtemp$ = ""refreshreturnudpRX:RXmsg$ = udp.read$if ucase$(word$(RXmsg$,1)) = "ACK" then gosub ACK 'echoed reply from successfully received message, original msg can be removed from queue else target$ = ucase$(word$(RXmsg$,1)) 'Target may be NodeName or GroupName or "ALL" or localIP address if (target$=localIP$) OR (target$=ucase$(nodename$)) OR (instr(ucase$(groupname$),target$)>0) OR (target$="ALL") then instruction$ = trim$(ucase$(word$(RXmsg$,2))) 'Instruction is second word of message data$ = "": getdata data$,RXmsg$," ",2 'extract any data that follows the instruction if word.find(ucase$(instructionslist$),instruction$) > 0 then if (ucase$(instruction$) <> "ACK") and (instr(ucase$(data$),"ID=") > 0) then udp.reply "ACK " + RXmsg$ 'ACKnowledge the incoming msg endif gosub instruction$ 'branch to action the corresponding instruction subroutine else udp.reply RXmsg$ + " INSTRUCTION NOT RECOGNISED" endif 'word.find endif '(target$=localIP$)endif 'ACKreturnACK:msg$ = "": getdata msg$, RXmsg$, " ", 1pos = word.find(retryq$,msg$,qdelimiter$)if pos > 0 then retryq$ = word.delete$(retryq$,pos,qdelimiter$)returnRETRY:if word.count(retryq$, qdelimiter$) > 0 thenif retryq$ <> "" then wlog "queue=" + retryq$ msg$ = word$(retryq$,1,qdelimiter$) 'grab first unACKed msg in the queue retryq$ = word.delete$(retryq$,1,qdelimiter$) 'chop msg off front of queue expire$ = "" WordParse expire$, msg$, "ID=", " " 'parse out ID= expire time if msg$ <> "" then 'compare expire time to current unix time if dateunix(date$) + timeunix(time$) > val(expire$) then Send "LOG ERROR: Node " + Nodename$ + " FAILED SEND - " + msg$ + " not ACKnowledged" else retryq$ = retryq$ + msg$ + qdelimiter$ udp.write netip$ + "255", udpport, msg$ wlog "retry " + msg$ endif endifendifreturnsendudp:sendmsg$ = sendmsg$ + " ID=" + str$(dateunix(date$) + timeunix(time$) + time2live, "%10d", 1)retryq$ = retryq$ + sendmsg$ + qdelimiter$udp.write netip$ + "255", udpport, sendmsg$returnsub SendQ(sendmsg$) sendmsg$ = sendmsg$ + " ID=" + str$(dateunix(date$) + timeunix(time$) + time2live, "%10d", 1)retryq$ = retryq$ + sendmsg$ + qdelimiter$udp.write netip$ + "255", udpport, sendmsg$end subsub Send(sendmsg$)udp.write netip$ + "255", udpport, sendmsg$end subsub GetData(ret$, v$, sep$, pos) 'extracts everything from the msg after the Instruction and puts into data$ (thanks cicciocb)local i, p, qp = 1for i = 1 to pos p = instr(p + 1, v$, sep$) if p > 0 then p = p + len(sep$)next iif p = 0 then ret$ = ""else q = instr(p+1, v$, sep$) if q = 0 then q = 999 ret$ = mid$(v$, p)end if end subsub WordParse(ret$, full$, search$, sep$) 'extracts value from option=value (thanks cicciocb)local p, b$p = instr(full$, search$)if p <> 0 then b$ = mid$(full$, p + len(search$)) ret$ = word$(b$, 1, sep$)else ret$ = ""end ifend subload:' Loads settings from file ... not yet fully implementeda$ = ""if FILE.EXISTS(filename$) > 0 then a$ = FILE.READ$(filename$) if WORD.GETPARAM$(a$,"nodename") <> "" then nodename$ = WORD.GETPARAM$(a$,"nodename") if WORD.GETPARAM$(a$,"ondelay") <> "" then ondelay = val(WORD.GETPARAM$(a$,"ondelay")) if WORD.GETPARAM$(a$,"onduration") <> "" then onduration = val(WORD.GETPARAM$(a$,"onduration")) if WORD.GETPARAM$(a$,"offdelay") <> "" then offdelay = val(WORD.GETPARAM$(a$,"offdelay")) if WORD.GETPARAM$(a$,"offduration") <> "" then offduration = val(WORD.GETPARAM$(a$,"offduration")) if WORD.GETPARAM$(a$,"udpport") <> "" then udpport = val(WORD.GETPARAM$(a$,"udpport"))endifreturnsave:' Saves settings to file ... not yet fully implementeda$ = ""if FILE.EXISTS(filename$) > 0 then a$ = FILE.READ$(filename$)WORD.SETPARAM a$, "nodename", nodename$WORD.SETPARAM a$, "ondelay", str$(ondelay)WORD.SETPARAM a$, "onduration", str$(onduration)WORD.SETPARAM a$, "offdelay", str$(offdelay)WORD.SETPARAM a$, "offduration", str$(offduration)WORD.SETPARAM a$, "udpport", str$(udpport)FILE.SAVE filename$, a$returnblink:if data$ <> "" then blinks = val(data$)ledstate = pin(led1pin)pin(led1pin) = led1offpause 200for count = 1 to blinksif led1off = 1 then pin(led1pin) = 0 else pin(led1pin) = 1pause 800pin(led1pin) = led1offpause 200next countpause 2000pin(led1pin) = ledstate 'Restore LED state to its previous statereturnblinkip:ledstate = pin(led1pin)blinkon = 150blinkoff = 300blinkpause = 1000blinkgap = 1400pin(led1pin) = led1offpause blinkpausefor pos = 1 to len(localIP$) digitchr$ = mid$(localIP$,pos,1) if digitchr$ = "." then pause blinkgap else if digitchr$ = "0" then digit = 10 else digit = val(digitchr$) for count = 1 to digit if led1off = 0 then pin(led1pin) = 1 else pin(led1pin) = 0 pause blinkon if led1off = 0 then pin(led1pin) = 0 else pin(led1pin) = 1 pause blinkoff next count pause blinkpause end ifnext pospause blinkgappin(led1pin) = ledstatereturnREPLY:udp.reply "Reply from " + Nodename$returnREPORT:udp.reply "Report from " + Nodename$ + " " + instructionslist$returnpressed:interrupt buttonpin, offpause debounceif pin(buttonpin) = 0 then start = millis else stop = millisif buttonmode = 1 then if pin(buttonpin) = 0 and (pin(relay1pin) = relay1noff) then gosub relay1on if pin(buttonpin) = 1 and (pin(relay1pin) <> relay1noff) then gosub relay1offelse if stop > start then if stop - start < longpress then gosub toggle1 else gosub blinkip endifendifinterrupt buttonpin, pressedreturnswitched:interrupt switchpin, offpause debounceif pin(switchpin) <> switchoff then if switchmode = 1 then gosub relay1on else gosub toggle1else if switchmode = 1 then gosub relay1offendifinterrupt switchpin, switchedreturnrelay1on:if pin(relay1pin) = relay1noff then if relay1noff = 0 then pin(relay1pin) = 1 else pin(relay1pin) = 0endifindicator = 0pin(led1pin) = 1-led1offhtml cssid$("butled", "background:red;")ondelaycountdown = -1offdelaycountdown = -1ondurationcountdown = -1offdurationcountdown = -1returnrelay1off:if pin(relay1pin) <> relay1noff then pin(relay1pin) = relay1noffindicator = 1pin(led1pin) = led1offhtml cssid$("butled", "background:green;")ondelaycountdown = -1offdelaycountdown = -1ondurationcountdown = -1offdurationcountdown = -1returncycle1on:COMMAND "m=" + ondelunits$if enabledelayon > 0 then ondelaycountdown = ondelay * m else ondelaycountdown = 0returncycle1off:COMMAND "m=" + offdelunits$if enabledelayoff > 0 then offdelaycountdown = offdelay * m else offdelaycountdown = 0returntoggle1:if pin(relay1pin) = relay1noff gosub relay1on else gosub relay1offenablescheduledon = 0enablescheduledoff = 0enablestat = 0enabledelayon = 0enabledelayoff = 0enabletimedon = 0enabletimedoff = 0ondelaycountdown = -1offdelaycountdown = -1ondurationcountdown = -1offdurationcountdown = -1returnEND '-------------------- End ---------------------
All of the functionality shown below is available... most is disabled by default but can be enabled individually 'as needed'.
See the Smart Switch project for details of how to download and install the 7-segment digital web fonts.