- Mon Aug 08, 2016 1:00 pm
#52486
EasyNet PIR node
In response to others, a 'PIR' option has been added to the 'Local button mode' dropdown list on the EasyNet Configuration page. The gpio00 button will still function normally to invoke flashing mode after a reset or power on, but the EasyNet program will then change the buttons behaviour according to the 'Local button mode' setting.
This now allows a PIR sensor module output to be mounted across (in parallel with) the gpio00 button to send a udp alert message when triggered. To allow use with either active high or active low triggers, a new 'let buttonlogic = 1' configuration option has been added in the new [PIRINIT] section just above [HOME]. The default buttonlogic = 1 mirrors the normal high state of the active low gpio00 button, so you need to change that to buttonlogic = 0 if your PIR trigger is active high.
A new [PIRALERT] function has been added below the [Home] code. By default a PIR alert will also activate the local relay if present, but the 2 appropriate relay entries can be commented out if not required.
You can of course test the new PIR functionality simply by selecting PIR as the 'Local button mode' from the Configuration page, then using the button without a PIR module attached, and it's worth pointing out that the same trigger functionality might be utilised by other digital output devices rather than the intended PIR modules. Just remember to level-match any output that is not 3.3v.
Separately but related, be aware that for default dev purposes the 'Debug mode' in Config is set to 'normal' whch will cause most events to send udp confirmation acknowledgements.
When you are happy that things are working correctly, change the 'Debug mode' setting to 'silent' to prevent unnecessary acknowledgements and just send the required udp messages.
This will make more sense if you monitor udp transmissions when triggerring a PIR alert with Debug mode still set to normal, because in addition to your required alert transmission you would also see both the 'up' and 'down' button interrupt events being acknowledged.
For the above PIR purposes, the PIR module used needs to give an active high or active low when triggered, unlike the differential pulses which a simple PIR detector gives out... PIR movement detectors 'sense' movement by detecting any IR heat differences between 2 (invisible) detection channels, which will each change as a hot body moves across them, causing pulses.
Cheaper PIR module simply have a thin plastic cap in front of the detector lens (if they have anything at all), which often just detracts from the signal sensivity rather than focusing the signal to enhance range - you can consider these as a simple pin-hole camera.
Better devices, including consumer targeted PIR units, have a special fresnel lens designed to enhance and differentiate between the 2 detector channels, so you can expect better range and sensitivity from these - effectively adding a telephoto lens.
Some PIR food for thought.
There are several PIR-activated external solar lights available for mounting on the side of buildings and fence posts etc. If they are hacked to accomodate an ESP device running ESP_Basic they can offer convenient self-contained maintenance-free wide-area PIR coverage wherever needed, and/or more specific alert notifications at the mailbox, gates and doors etc.
Usually they have 1 or more solar-charged batteries fed into a regulator to drive the electronics. Sometimes the electronics uses 3.3v which makes things relatively easy for integrating an ESP, but if not, it may be feasible to include a separate cheapo 'buck' power supply module just for the ESP, in which case you will also need to consider logic level matching.
These type of PIR-activated solar lights usually incorporate a light sensor to prevent the lights unnecessarilly being switched on during the daytime and draining the battery, but that is not ideal if you also require daytime alerts. Unfortunately the light sensor usually controls the PIR circuits detection at the chip input, rather than by directly affecting switching of the output leds.
A relatively straightforward way to get around that problem is to stick insulating tape over the light sensor so it thinks it's always dark. This will of course cause the lights to draw current during the daytime alerts, possibly draining the battery too quickly, but it may me possible to snip off some of the LEDs to reduce current consumption and allow the battery to last long enough.
If you just require PIR alerts and aren't bothered about the light then obviously just leave the LEDs disconnected.
A more satisfying solution could be to add a light sensor capabilty to the ESP (which is always receiving PIR alerts) and get the ESP to control the switching of the LEDs only during the night time (via an appropriate transistor or relay).
I haven't overwritten the original postings, I've provided the new modified code here, and the same code can ether be configured as the PIR sender node, or as the receiving Relay node (the default).
Code: Select all'EasyNet Framework 1b - Still configured for SonOff Relay Module, but with optional PIR support added
memclear
let debugmode = "normal" 'debugmode options are: silent, normal, verbose
let ledpin = 13
let relaypin = 12
let dhtsensor = 11
let dhtpin = 14
let settemp = 24
let sethumid = 50
let frequency = 5000 ' sensor read update frequency
let settemp = 24
let sethumid = 50
let statmode = "TooHot"
let frequency = 5000 ' sensor read update frequency
let ledlogic = 1 'Default led pin off state (allows configuring led pin for active high or active low operation)
let relaylogic = 0 'Default relay pin off state (allows configuring relay pin for active high or active low operation)
let buttonpin = 0 'Using onboard GOIO00 flashing button by default, change to suit (needs pullup resistor).
interrupt buttonpin, [PRESSED]
let nowait = 0
let localIP = ip()
gosub [IPSPLIT]
let shoutmsg = "All Blinks" ' The default msg shown in the broadcast msg window
gosub [READVARS]
if (title == "" or title == " ") then let title = "EasyNet framework 1b - configured for Sonoff, but with PIR option"
if (localname == "" or localname == " ") then let localname = "Node" & nodeIP
if globalname == "" then let globalname = "ALL"
if groupname == "" then let groupname = "Relay"
if udpport == "" then let udpport = "5001"
if (description == "" or description == " ") then let description = "Network Relay module. "
if debugmode == "" then let debugmode = "normal"
if buttonmode == "" then let buttonmode = "MultiMode"
if userpage == "" then let userpage = "Normal"
if startmode == "" then let startmode = "Off"
if startmode == "On" then
if relaylogic == 0 then io(po,relaypin,1) else io(po,relaypin,0)
if ledlogic == 0 then io(po,ledpin,1) else io(po,ledpin,0)
else
if relaylogic == 0 then io(po,relaypin,0) else io(po,relaypin,1)
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1)
endif
udpbegin udpport
udpbranch [UDPMAIN]
[DHTINIT]
if startmode = "Stat" then
dht.setup(dhtsensor, dhtpin)
timer frequency, [HOME]
else
timer 0
endif
[PIRINIT]
'This expects a PIR output to be connected across (in parallel with) the gpio00 button
let buttonlogic = 1 'Default button off state (allows configuring a paralled PIR output for active high or active low)
let PIRsettleTime = 1000 'Adjust for whatever time is needed for your PIR to stabilise and stop false-triggering
delay PIRsettleTime 'Simple crude delay to prevent sending false udp trigger alerts while the PIR stabilises
[HOME]
cls
if startmode == "UserOnOff" then goto [USERONOFF]
print " "
button " ? " [HELP]
wprint " "
wprint title
wprint " "
wprint "- Developed on V2 Alpha 24"
print " "
if startmode == "Stat" then goto [STATMODE]
if startmode == "UserToggle" then goto [USERTOGGLE]
html "<BR>"
html "NODE DETAILS "
html "<BR>" & "<BR>"
html "Local name: " & localname
html "<BR>"
html "Global name: " & globalname
html "<BR>"
html "Group name: " & groupname
html "<BR>"
html "Local IP address: " & localIP
html "<BR>" & "<BR>"
if description <>"" then html "Description: " & description
wprint "<BR><BR><BR>"
gosub [SENDMSG]
button "ON" [RELAYON]
wprint " "
button "Toggle Relay" [TOGGLE]
wprint " "
button "OFF" [RELAYOFF]
wprint "<BR><BR>"
button "Cycle ON [OFF]" [CYCLEON]
wprint " "
wprint "On delay: " & ondelay
wprint " "
wprint "On duration: " & onduration
wprint "<BR><BR>"
button "Cycle OFF [ON]" [CYCLEOFF]
wprint " "
wprint "Off delay: " & offdelay
wprint " "
wprint "Off duration: " & offduration
wprint "<BR><BR>"
wprint "Local button mode = " & buttonmode
wprint "<BR><BR>"
wprint " "
print "<BR>"
button "Configuration" [CONFIG]
wait
[PIRALERT]
let PIRdestination = "ALL" 'Change to the required receiver node, else alerts will be sent to ALL group of nodes
let PIRalertMsg = localname & " " & "PIR alert triggered" 'Change for whatever message you wish to be transmitted
udpwrite netIP & "255", val(udpport), PIRdestination & " " & PIRalertMsg
let oldstate = io(laststat,ledpin)
io(po,ledpin,ledlogic)
if relaylogic == 0 then io(po,relaypin,1) else io(po,relaypin,0) 'Comment out if you don't want to use the local relay
delay 200
if ledlogic == 0 then io(po,ledpin,1) else io(po,ledpin,0)
let PIRtimeout = 5000 'Time to wait before sending retriggered alert
delay PIRtimeout - 250
if relaylogic == 0 then io(po,relaypin,0) else io(po,relaypin,1) 'Comment out if you don't want to use the local relay
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1)
delay 200
io(po,ledpin,oldstate)
goto [HOME]
[TOGGLE]
if debugmode <> "silent" then udpreply localname & " Toggle acknowledged"
if io(laststat,relaypin) = 0 then io(po,relaypin,1) else io(po,relaypin,0)
if io(laststat,ledpin) = 0 then io(po,ledpin,1) else io(po,ledpin,0)
goto [HOME]
[CYCLEON]
if debugmode <> "silent" then udpreply localname & " CycleOn acknowledged"
if len(params) > 0 then gosub [GETCYCLEPARS]
if ondelay <> 0 then delay ondelay
if relaylogic == 0 then io(po,relaypin,1) else io(po,relaypin,0)
if ledlogic == 0 then io(po,ledpin,1) else io(po,ledpin,0)
if onduration == 0 then goto [HOME]
delay onduration
goto [RELAYOFF]
[CYCLEOFF]
if debugmode <> "silent" then udpreply localname & " CycleOff acknowledged"
if offdelay <> 0 then delay offdelay
if relaylogic == 0 then io(po,relaypin,0) else io(po,relaypin,1)
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1)
if offduration == 0 then goto [HOME]
delay offduration
goto [RELAYON]
[RELAYON]
if debugmode <> "silent" then udpreply localname & " On acknowledged"
if io(laststat,relaypin) <> relaylogic then goto [HOME]
if relaylogic == 0 then io(po,relaypin,1) else io(po,relaypin,0)
if ledlogic == 0 then io(po,ledpin,1) else io(po,ledpin,0)
goto [HOME]
[RELAYOFF]
if debugmode <> "silent" then udpreply localname & " Off acknowledged"
if io(laststat,relaypin) == relaylogic then goto [HOME]
if relaylogic == 0 then io(po,relaypin,0) else io(po,relaypin,1)
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1)
goto [HOME]
[STATMODE]
wprint "<BR><BR>"
if statmode == "TooHot" then goto [TOOHOT]
if statmode == "TooCold" then goto [TOOCOLD]
if statmode == "TooWet" then goto [TOOWET]
if statmode == "TooDry" then goto [TOODRY]
[TOODRY]
wprint " Irrigation switch"
wprint "<BR><BR>"
wprint "Humidity=" & dht.hum()
wprint "<BR><BR>"
button "<" [HUMID<]
wprint " "
wprint sethumid
wprint " "
button ">" [HUMID>]
if dht.hum() < sethumid and io(laststat,relaypin) == relaylogic then goto [RELAYON]
if dht.hum() > sethumid and io(laststat,relaypin) <> relaylogic then goto [RELAYOFF]
wprint "<BR><BR><BR>"
button "Configuration" [CONFIG]
wait
[TOOWET]
wprint " Ventilation switch"
wprint "<BR><BR>"
wprint "Humidity=" & dht.hum()
wprint "<BR><BR>"
button "<" [HUMID<]
wprint " "
wprint sethumid
wprint " "
button ">" [HUMID>]
if dht.hum() > sethumid and io(laststat,relaypin) == relaylogic then goto [RELAYON]
if dht.hum() < sethumid and io(laststat,relaypin) <> relaylogic then goto [RELAYOFF]
wprint "<BR><BR><BR>"
button "Configuration" [CONFIG]
wait
[TOOCOLD]
wprint " Heating switch"
wprint "<BR><BR>"
wprint "temp="
wprint dht.temp()
wprint "<BR><BR>"
button "<" [TEMP<]
wprint " "
wprint settemp
wprint " "
button ">" [TEMP>]
if dht.temp() < settemp and io(laststat,relaypin) == relaylogic then goto [RELAYON]
if dht.temp() > settemp and io(laststat,relaypin) <> relaylogic then goto [RELAYOFF]
wprint "<BR><BR><BR>"
button "Configuration" [CONFIG]
wait
[TOOHOT]
wprint " Cooling Fan switch"
wprint "<BR><BR>"
wprint "temp="
wprint dht.temp()
wprint "<BR><BR>"
button "<" [TEMP<]
wprint " "
wprint settemp
wprint " "
button ">" [TEMP>]
if dht.temp() > settemp and io(laststat,relaypin) == relaylogic then goto [RELAYON]
if dht.temp() < settemp and io(laststat,relaypin) <> relaylogic then goto [RELAYOFF]
wprint "<BR><BR><BR>"
button "Configuration" [CONFIG]
wait
[HUMID>]
let sethumid = sethumid + 1
goto [HOME]
[HUMID<]
let sethumid = sethumid - 1
goto [HOME]
[TEMP>]
let settemp = settemp + 1
goto [HOME]
[TEMP<]
let settemp = settemp - 1
goto [HOME]
[USERONOFF]
wprint |<body>|
wprint |<div style="text-align: center;">|
wprint |<table style="text-align: left; width: 100%;" border="0"|
wprint | cellpadding="2" cellspacing="2">|
wprint | <tbody>|
wprint | <tr>|
wprint | <td style="text-align: right;">|
button " ? " [HELP]
wprint |</td>|
wprint | <td style="text-align: center;color: rgb(102, 51, 255);"><big><big>|
wprint localname
wprint | </big></big></td>|
wprint | <td style="text-align: left;">|
button " ! " [CONFIG]
wprint |</td>|
wprint | </tr>|
wprint | </tbody>|
wprint |</table>|
print " "
wprint |<br>|
wprint "<BR><BR><BR>"
wprint "Status="
if io(laststat,relaypin) == relaylogic then
wprint |<big style="color: rgb(0, 153, 0);">OFF|
wprint |</big><br> |
else
wprint |<big style="color: rgb(204, 0, 0);">ON|
wprint |</big><br> |
endif
wprint "<BR><BR>"
wprint |<big><big>|
button "ON" [RELAYON]
wprint " "
button "OFF" [RELAYOFF]
wprint | </big></big><br>|
wprint |</div>|
wprint |</body>|
wprint "<BR><BR>"
wait
[USERTOGGLE]
wprint "<BR><BR><BR><BR><BR><BR>"
wprint |<!DOCTYPE html>|
wprint |<html>|
wprint |<head>|
wprint |<style>|
wprint | .bigbutton, input[type="button"], input[type="submit"] { |
wprint | display: inline-block;|
wprint | padding: 15px 25px;|
wprint | font-size: 24px;|
wprint | cursor: pointer;|
wprint | text-align: center;|
wprint | color: #fff;|
if io(laststat,relaypin)=0 then
wprint |background-color: #4CAF50; /* Green */|
else
wprint |background-color: #f44336; /* Red */|
endif
wprint | border: 2px solid black;|
wprint | border-radius: 15px;|
'wprint | box-shadow: 0 9px #999;|
wprint |}|
wprint | .box, input[type="button"], input[type="submit"] { |
wprint |}|
wprint |</style>|
wprint |</head>|
wprint |<body>|
wprint |<div style="font-size: 32px; text-align: center;">|
if io(laststat,relaypin) = 0 then button "ON" [TOGGLE] else button "OFF" [TOGGLE]
wprint |</div>|
wprint |</body>|
wprint |</html>|
wait
[READVARS]
read Title title
read Name localname
read Global globalname
read Group groupname
read Description description
read Userpage userpage
read Startmode startmode
read Debugmode debugmode
read Buttonmode buttonmode
read UDPport udpport
read Ondelay tmp
if tmp == "" then let ondelay = 0 else let ondelay = val(tmp)
let ondelay = val(tmp)
read Offdelay tmp
if tmp == "" then let offdelay = 2000 else let offdelay = val(tmp)
read Onduration tmp
if tmp == "" then let onduration = 5000 else let onduration = val(tmp)
read Offduration tmp
if tmp == "" then let offduration = 9000 else let offduration = val(tmp)
read Blinks tmp
if tmp == "" then let numblinks = 5 else let numblinks = val(tmp)
return
[SAVE]
if debugmode <> "silent" then udpreply localname & " Save to Flash acknowledged"
write Title title
write Name localname
write Global globalname
write Group groupname
write Description description
write UDPport udpport
write Debugmode debugmode
write Buttonmode buttonmode
write Ondelay ondelay
write Offdelay offdelay
write Onduration onduration
write Offduration offduration
write Blinks numblinks
write Startmode startmode
write Userpage userpage
goto [DHTINIT]
return
[BLINKS]
if debugmode <> "silent" then udpreply localname & " Blinks acknowledged. Params=" & params
let oldstate = io(laststat,ledpin)
io(po,ledpin,ledlogic)
if len(params) > 0 then let numblinks = val(params)
let params = ""
delay 200
for count = 1 to numblinks
if ledlogic == 0 then io(po,ledpin,1) else io(po,ledpin,0)
delay 600
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1)
delay 400
next count
delay 2000
io(po,ledpin,oldstate)
goto [HOME]
[BROADCAST]
if instr(upper(shoutmsg),"LOCAL") == 1 then goto [LOCAL]
udpwrite netIP & "255", val(udpport), shoutmsg
wait
[LOCAL]
let msg = shoutmsg
'udpreply msg
goto [MAIN]
[SENDMSG]
html " Broadcast message "
textbox shoutmsg
button "Send" [BROADCAST] ' broadcast the message
wprint " "
wprint " (use name LOCAL to respond to commands sent from the same local node, eg: LOCAL BLINKIP)."
html "<BR>" & "<BR>"
return
[UDPMAIN]
let msg = udpread()
let lastmsg = msg
[MAIN]
if debugmode == "verbose" then udpreply localname & " msg received: " & msg
let name = upper(word(msg, 1))
let command = ""
let params = ""
let pos = len(name)
if len(msg) > pos then command = upper(word(msg, 2))
let pos = instr(upper(msg),command) + len(command)
if len(msg) > pos then params = mid(msg,(pos)) else params = ""
if debugmode = "verbose" then udpreply localname & " Name=" & name
if debugmode = "verbose" then udpreply localname & " Command=" & command
if debugmode = "verbose" then udpreply localname & " Params=" & params
if instr(upper(localname),name) > 0 then name = upper(localname) ' complete partial name to full name
if name == "LOCAL" then goto [LOCAL_COMMANDS] ' handle locally-sent commands
if name == upper(localname) then goto [LOCAL_COMMANDS] ' handle localname commands
if name == upper(groupname) then goto [GROUP_COMMANDS] ' handle any group commands
if name == upper(globalname) then goto [GLOBAL_COMMANDS] ' handle any global commands
if debugmode <> "silent" then udpreply localname & " Error: NAME not recognised in " & msg
wait
[LOCAL_COMMANDS]
'let lastmsg = msg
' Add any new unique local commands here (change the test udreply to gosub to your appropriate subroutine handler
if command == upper("ON") then goto [RELAYON]
if command == upper("OFF") then goto [RELAYOFF]
if command == upper("CYCLEON") then goto [CYCLEON]
if command == upper("CYCLEOFF") then goto [CYCLEOFF]
if command == upper("ONDELAY") then goto [ONDELAY]
if command == upper("OFFDELAY") then goto [OFFDELAY]
if command == upper("ONDURATION") then goto [ONDURATION]
if command == upper("OFFDURATION") then goto [OFFDURATION]
if command == upper("BUTTONMODE") then goto [BUTTONMODE]
if command == upper("TOGGLE") then goto [TOGGLE]
if command == upper("SAVE") then goto [SAVE]
gosub [COMMON_COMMANDS]
if debugmode <> "silent" then udpreply localname & " Error: COMMAND " & command & " not recognised in " & msg
return
[COMMON_COMMANDS]
' Commands recognised by all nodes. Add any new common commands here
if command == upper("Report") then goto [REPORT]
if command == "?" then goto [DECLARE]
if command == upper("Blinks") then goto [BLINKS]
if command == upper("BlinkIP") then goto [BLINKSHORTIP]
if command == upper("BlinkShortIP") then goto [BLINKSHORTIP]
if command == upper("BlinkFullIP") then goto [BLINKFULLIP]
if command == upper("Exit") then goto [EXIT]
if command == upper("Reset") then goto [RESET]
if debugmode <> "silent" then udpreply localname & " Error: common COMMAND " & command & " not recognised in " & msg
return
[GROUP_COMMANDS]
' Sent prefixed by groupname.
' Add any new group-only commands here, eg: "Groupname NewGroupCommand"
goto [LOCAL_COMMANDS]
[GLOBAL_COMMANDS]
' Sent prefixed by globalname, eg: "Globalname NewGlobalCommand"
' Add any new global-only commands here,
goto [LOCAL_COMMANDS] ' branch to look for local_commands
[DECLARE]
if debugmode <> "silent" then udpreply localname & " Declare IP acknowledged "
udpreply localname & " " & localIP
goto [HOME]
return
[REPORT]
if debugmode <> "silent" then udpreply localname & " Report request acknowledged "
udpreply "Sending data" ' change to include whatever info needs to be sent back
return
[ONDELAY]
if debugmode <> "silent" then udpreply localname & " OnDelay " & params & " acknowledged"
let ondelay = val(params)
params = ""
goto [HOME]
[OFFDELAY]
if debugmode <> "silent" then udpreply localname & " OffDelay " & params & " acknowledged"
let offdelay = val(params)
params = ""
goto [HOME]
[ONDURATION]
if debugmode <> "silent" then udpreply localname & " OnDuration " & params & " acknowledged"
let onduration = val(params)
params = ""
goto [HOME]
[OFFDURATION]
if debugmode <> "silent" then udpreply localname & " OffDuration " & params & " acknowledged"
let offduration = val(params)
params = ""
goto [HOME]
[BLINKFULLIP]
if debugmode <> "silent" then udpreply localname & " BlinkIP acknowledged "
let oldstate = io(laststat,ledpin)
let blinkon = 200
let blinkoff = 400
let blinkpause = 1000
let blinkgap = 1400
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1) ' turn led off
delay blinkpause
for pos = 1 to len(localIP)
let digitchr = mid(localIP,pos,1)
if digitchr == "." then
delay blinkgap
else
if digitchr = "0" then let digit = val("10") else digit = val(digitchr)
for count = 1 to digit
if ledlogic == 0 then io(po,ledpin,1) else io(po,ledpin,0)
delay blinkon
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1)
delay blinkoff
next count
delay blinkpause
end if
next pos
delay blinkgap
io(po,ledpin,oldstate)
if nowait == 0 then wait else nowait = 0
return
[BLINKSHORTIP]
if debugmode <> "silent" then udpreply localname & " BlinkIP acknowledged "
let oldstate = io(laststat,ledpin)
let blinkon = 200
let blinkoff = 400
let blinkpause = 1000
let blinkgap = 1400
let ip = val(nodeIP)
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1) ' turn led off
delay blinkpause
let ipstr = str(ip)
let iplength = len(ipstr)
for pos = 1 to iplength
let digit = mid(ipstr,pos,1)
for temp = 1 to digit
if ledlogic == 0 then io(po,ledpin,1) else io(po,ledpin,0)
delay blinkon
if ledlogic == 0 then io(po,ledpin,0) else io(po,ledpin,1)
delay blinkoff
next temp
delay blinkpause
next pos
delay blinkpause
io(po,ledpin,oldstate)
if nowait == 0 then wait else nowait = 0
return
[IPSPLIT]
pos = instrrev(localIP,".")
netIP = left(localIP,pos)
nodeIP = mid(localIP,pos+1)
return
[HELP]
cls
print " "
button "X" [HOME]
wprint " "
wprint title & " - HELP"
print ""
wprint "Syntax: NODENAME COMMAND [OPTIONAL PARAMETERS] "
wprint " (name and commands are NOT case-sensitive, parameters ARE case-sensitive)"
wprint "<BR>"
wprint "Example: LOCAL BLINKS 12 "
wprint " (use node name of LOCAL to address commands to local node instead of remote network nodes)"
wprint "<BR><BR>"
wprint "ON - turns relay instantly On and it stays On."
wprint "<BR>"
wprint "OFF - turns relay instantly Off and it stays Off."
wprint "<BR>"
wprint "TOGGLE - instantly changes relay state."
wprint "<BR>"
wprint "CycleON - turns relay On after optional OnDelay, then optionally turns back Off after optional OnDuration."
wprint " (useful for automatic lights etc)"
wprint "<BR>"
wprint "OnDelay - 0 for no On delay."
wprint "<BR>"
wprint "OnDuration - 0 to stay On."
wprint "<BR>"
wprint "CycleOFF - turns relay Off after optional OffDelay, then optionally turns back On after optional OffDuration."
wprint " (useful for power-down reboots of routers etc) "
wprint "<BR>"
wprint "OffDelay - 0 for no Off delay."
wprint "<BR>"
wprint "OffDuration - 0 to stay Off. "
wprint "<BR>"
wprint "Blinks [numblinks] - blinks the local led to aid location. Optional parameter over-rides default of 5 blinks."
wprint "<BR>"
wprint "BlinkFullIP - locally blinks the full IP byte digits (10 blinks for 0)."
wprint "<BR>"
wprint "BlinkShortIP - locally blinks the last IP byte digits (the wifi subnet address will already be known)."
wprint "<BR>"
wprint "Report - returns the nodes IP address via UDP. "
wprint "<BR>"
wprint "Save - saves variables to non-volatile flash memory."
wprint "<BR>"
wprint "Reset - restarts the node. "
wprint "<BR>"
wprint "Exit - shuts down the node. "
wprint "<BR>"
wprint "ButtonMode - allows different behaviour for local button. "
wprint " FlipSwitch allows standard flip-type light switch to be used instead of momentary button."
wprint " MultiMode allows quick blip to Toggle relay, or press and quck "
wprint " hold (less than 1 sec) for BlinkShortIP, or press and long hold (greater than 1.5 sec) for BlinkFullIP."
wprint "<BR><BR>"
wprint "This script is configured for the Sonoff module, but is adaptable for alternative "
wprint "switched relay modules."
wprint "<BR>"
wprint "Sonoff pins - button=0, led=12, relay=13. Ledlogic=0 (active low), relaylogic=1 (Sonoff relay is active high)."
wprint "<BR><BR>"
button "Home" [HOME]
wait
[CONFIG]
cls
print " "
button "X" [DHTINIT]
wprint " "
wprint title & " - CONFIG"
print " "
html "<BR>"
html "Title: "
textbox title
html "<BR><BR>"
html "Local name: "
textbox localname
wprint " "
html "Group name: "
textbox groupname
html " "
html "Global name: "
textbox globalname
html "<BR><BR>"
html "UDP port "
textbox udpport
html "<BR><BR>"
html "Description: "
textbox description
html "<BR><BR>"
wprint "Local button mode "
dropdown "MultiMode,BlinkFullIP,BlinkShortIP,Toggle,FlipSwitch,PIR" buttonmode
wprint " "
wprint " selects different behaviour for local button. MultiMode is button-speed dependent (see Help ?)."
wprint "<BR><BR>"
wprint "Start mode"
dropdown "On,Off,Stat,UserToggle,UserOnOff" startmode
wprint " "
wprint " Allows selecting a pre-defined startup mode."
wprint "<BR><BR>"
wprint "DHT sensor"
dropdown "None, 11, 21, 22" dhtsensor
wprint " "
wprint " Stat mode "
wprint " "
dropdown "TooHot, TooCold, TooWet, TooDry" statmode
wprint " "
wprint " Temperature setting="
textbox settemp
wprint " Humidity setting="
textbox sethumid
wprint "<BR><BR>"
wprint " On delay: "
textbox ondelay
wprint " "
wprint " "
wprint " On duration: "
textbox onduration
wprint "<BR><BR>"
wprint " Off delay: "
textbox offdelay
wprint " "
wprint " "
wprint " Off duration: "
textbox offduration
'wprint " <BR><BR><BR>"
wprint "<BR><BR>"
wprint "Number of Blinks: "
textbox numblinks
wprint "<BR><BR>"
wprint "Debug mode "
dropdown "silent,normal,verbose" debugmode
wprint " "
wprint " UDP messages - silent=none, normal=acknowledgements, verbose=debug info."
wprint "<BR><BR><BR>"
button "Home" [DHTINIT] ' don't save edits
wprint " "
wprint " "
button "Save" [SAVE] ' save details to persistent memory
wprint " "
wprint " "
wprint "HOME loses changes at power-off, SAVE holds changes in non-volatile flash memory. "
wait
[BUTTONMODE]
if debugmode <> "silent" then udpreply localname & " ChangeButtonMode acknowledged"
let buttonmode = params
let params = ""
goto [HOME]
return
[PRESSED]
if debugmode <> "silent" then udpwrite netIP & "255", val(udpport), localname & " Local button pressed"
if buttonmode == "PIR" then
if io(laststat,buttonpin) <> buttonlogic then goto [PIRALERT]
endif
if buttonmode == "FlipSwitch" then
if io(laststat,buttonpin) = 0 then goto [RELAYON] else goto [RELAYOFF]
endif
if buttonmode == "Toggle" then
if io(laststat,buttonpin) = 0 then goto [TOGGLE]
endif
if buttonmode == "BlinkShortIP" then
if io(laststat,buttonpin) = 0 then goto [BLINKSHORTIP]
endif
if buttonmode == "BlinkFullIP" then
if io(laststat,buttonpin) = 0 then goto [BLINKFULLIP]
endif
if io(laststat,buttonpin) = 0 then let start = millis() else let stop = millis()
if stop > start then
if stop-start < 500 then goto [TOGGLE]
if stop-start < 1000 then goto [BLINKSHORTIP]
if stop-start > 1500 then goto [BLINKFULLIP]
endif
goto [HOME]
[EXIT]
print "<BR>" & "Node " & upper(localname) & " with IP address " & localIP & " has been shut down."
udpwrite netIP & "255", val(udpport), "Node " & upper(localname) & " has been shut down." & "<BR>"
for count = 1 to 5
po ledpin 0
delay 70
po ledpin 1
delay 200
next count
end
[RESET]
reboot