Place to put your Basic demos and examples

Moderator: Mmiscool

User avatar
By Electroguard
#46944 ESP_Basic Driving Lessons - Chapter 5.

ESP_Basic Racehorse
It may seem a bit late to be talking about ESP hardware at this stage, but it probably wouldn't have been appreciated or made much sense until you dipped your toes in the water to know what I'm talking about.

ESP_Basic can run on just about any ESP-8266 device, and you may already have a shed-load of different ESP's lying around... but there are some less-than-obvious different hardware usage considerations that perhaps you may not have already thought of. It's obviously a matter of 'horses for courses', but sometimes the best course may not be so obvious... there could be a big difference in what I might choose to use for a final working project compared to what I would prefer to develop the project on. For development I want quick convenience, so I would prefer an ESP dev module that offers easy connection, good visual feedback, and is as self-contained as possible - rather than a tiny ESP sitting in the middle of a tangled fragile spiders-web.

Because of the nature of ESP_Basic, making the right choice of ESP can offer a lot more benefit than it could otherwise offer with the Arduino compiler etc. With the compiler, most of the time is spent editing in the IDE or uploading the script, which can take an age... so continual reflashing of each re-compiled program change is just an in-escapable fact of life (unless you're losing half your flash memory for OTA), so it doesn't really matter too much what sprawling uarts and birds-nest wiring are attached... cos it aint going anywhere in a hurry!

Compare that to ESP_Basic, which you only flash initially ONCE with ESP_Basic... then all further communication for script loading and saving is done over wifi from your browser.
So after originally flashing for the first time, you shouldn't need to use a uart to flash again until you wish to upgrade to a newer release or perhaps want to make a clean start because of some weird symptoms. That's quite a significant usage difference, and ESP_Basic can take much better advantage of a self-contained module without bits dangling all over the place.

That may be better appreciated by explaining what I use - and how I use it - then the benefits should become more apparent.

http://www.ebay.co.uk/itm/ESP8266-WIFI-Serial-Kit-Development-Board-Test-Wireless-Board-Full-IO-Leads-DY-/262314535314?hash=item3d132a2992:g:bhsAAOSw~OVW1Ytd

There is a new version of the Serial Dev Kit Module available from the far east for less than £4 on ebay. This new version comes supplied with a 3xAA battery box (the module has onboard 3.3v regulator) which hasn't yet been soldered to the board - and for ESP_Basic dev work it may never need to be... because the module can be conveniently powered by the usb of an onboard uart (same CH340 drivers that you've probably already got installed for your arduinos).

It has convenient leds and breakout pins for the gpios, a gpio00 flashing jumper, and a sliding on/off switch... so it is completely self-contained, and can be powered by the usb cable which comes with it. It doesn't even need plugging into a breadboard... it just sits on the desk - or even in your hand - 'as-is' (the current A21 version of ESP_Basic requires you to add a pull-up resistor to any pin you wish to use as input, but hopefully that may change).

If I need to reflash the ESP, it's just a matter of fitting the tomb-stone jumper link to gpio00 then flicking the power switch off and back on, then remove the jumper again.
If it gets it's nickers in a twist and needs a reboot, I just flick the switch off and back on - otherwise it pretty much stays on and connected 24 hours a day... and is ready to connect straight back to from the browser each day.

It was so convenient that I bought another 2 - so now I can have one with my big EasyNet Demonstrator script I'm doing, another for trying out new releases and/or other scripts, and another with a previous older release of ESP_Basic just for comparisons and fallback etc.

Trying a script on different versions is as ridiculously quick and simple as doing a CTRL A and CTRL C on the edit window, unplug the usb cable and put that module to one side, plug the cable into a different module, wait till it boots up and connects, then CTRL V the script and try it.

If that doesn't impress you, then you really are a techo-virgin!

Which means that you probably also won't be impressed by the fact that it has facility to switch from the onboard 4Mb ESP202 to an onboard empty ESP01 socket so you can flash as many 'production' ESP01's direct from your dev project module as you need to!

So yes, you may already have ESPs laying around, but I doubt you'd find a better matched horse for the ESP_Basic race-course than this... that's not to say that there aren't any better available, but I sure don't have the need or incentive to look for them. I don't know what documentation may exist for it now, but at the time I got mine there was zilch, so I checked things out for myself and labelled up the pic below to show eveything relevent (including the mis-labelling of TX and RX on the pcb).

Image
User avatar
By Electroguard
#46959 ESP_Basic Driving Lessons - Chapter 6.

Playtime
ESP_Basic has so many interesting 'building blocks' to play with that's it's difficult to know where to start 'dabbling' first.
It helps to have some sort of 'goal' in mind, because then you can begin by focusing on the available tools that might help you attain that goal - but it's easier said than done if you don't yet know what tools are available and what you can do with them.

So we'll start out by making ourselves a handy little re-usable toolbox which we can put any newly-aquired tools into and conveniently keep ready for future re-use. It will only be an intermediate step towards our ultimate goal of creating the 'key' component at the heart of almost every system - a switched relay controller - but the Toolbox will include such complex diversity as to make you choke and splutter on your coffee if you were not fore-warned of what's to come. Don't worry though, because if you follow things through step by step, you will easily aquire all the knowledge and expertise to utilise any and all of that complex diversity for yourself in your own projects... in fact the re-uable Toolbox will already provide most of the diverse functionality for you anyway, you'll just need to tailor it each time to suit your own specific needs.

Please remember that I'm not an expert and so whatever I say is not necessarilly the best way of doing something, it's merely the best way that I know of... simply because I don't yet know any better! I am still learning daily, so my attitude is that any method of accomplishing any task is the best way until learning something better.
And that's one of the great things about ESP_Basic, because you don't need to be an experienced programmer to make it do some very clever tricks, and you can slowly learn how to use those tricks without shame as you progress.

Variables and branches are case-sensitive and a possible cause of problems, so something I've learned to do for my own benefit is to keep all [BRANCHES} in uppercase (which makes all branch references immediately apparent), likewise I keep all variable names in lowercase (unless they include obvious beneficial uppercase abbreviations such as in 'IPaddress'), and I reserve 'Proper' case for file i/o variables to differentiate them from the same name ordinary variables, eg: 'read Name name', or 'write Description description'.
This is not a law that must be obeyed, it is simply a private convention which I've found makes life easier for me, especially when the scripts start growing into multiple pages and my tiny attention span and tunnel vision can't keep track of such things in my head.
Another private convention is that I call a sequential list of ESP_ Basic lines a script, but I call the same thing a program when it is 'Run' and doing whatever it was 'programmed' to do - I only mention it to prevent the different terminology causing any unnecessary confusion later.

So we'll start our script with the memclear instruction to remove all previous variables - but you're old enough and ugly enough for me not to be holding your hand all the time... therefore I will give a block of example code for you to copy and paste, then Save, then Run to see what the results looks like, then you can browser Back to look at the script in the Edit page while I point out anything that might be noteworthy.
We're expecting our script to grow, and possibly branch off in different directions of interest, so we'll give it a title and version number for easy recognition in the future. Also, ESP_Basic is evolving faster than a hormonal teenager (and at times can be just as moody and unpredictable) so it could be helpful (even essential) to know what ESP_Basic release version a program has been written for. Command syntax can change, and new commands are frequently added, therefore a script that works now on this current release may not work on anything older, nor on a subsequent future release - so we'll include the ESP_Basic release version for future reference.
You will notice that print adds a line after the text, which in this instance makes a pretty neat job of our title bar - but be careful where you add subsequent 'print's because unwanted lines can look quite messy. In general it is better to be using wprint and terminating the lines by adding & "<BR>" which inserts a line 'break' (carraige_return plus line_feed), ie: wprint "Hello world" & "<BR>".
You should be aware that you can't add horizontal white space by inserting extra spaces (or tab chrs) cos they just get ignored - it's a browser thing, and you'll see that the forum does the same thing to your postings - and mine - therefore it's gonna be doing it to this example also... so you won't have a clue what I'm waffling on about! Just take note that there is only 1 space between every word, and take my word that the source had a lot more spaces in it than that. I will show you later how to add horizontal white space, but it's easy enough to add some vertical white space though, just by inserting as many blank lines as you want by using: wprint "<BR><BR><BR><BR><BR>".

Then we add the first of our goodies into our toolbox... a couple of web buttons.
It would be a bit of a pointless example if they didn't do anything, so let's add a couple of minimal subroutines for them to branch to for turning the onboard gpio01 led On and Off. They could just as well be switching a different gpio connected to a relay of course, but let's keep things generic and suitable for everyone for the moment... it's easy enough to tailor things to individual needs later.

Have a bit of a play until you are confident you know what all the lines of the script are doing, then we'll see about doing some improvements. Make sure you are first familiar with what is being done and why, because when we move on we will be picking up the pace and introducing some advanced functionality into our Toolbox - which is easy enough to understand if you follow things as we go along, but may get a bit too complex and over-whelming to try to reverse-engineer from the final completed project.

So a word of advice before we start... don't shy away from trying the scripts! These 'driving lessons' contain all the source scripts so you have nothing to lose, and it takes only seconds to select_all, copy, then paste in a completely different script, then save it and run it.

One of the brilliant things about ESP_Basic is that you can be running 2 entirely different scripts within the space of 1 minute and without any hardships. The same applies to ANY ESP_Basic scripts from ANYWHERE... don't be frightened to try them, because it only takes a few seconds, and the worst they can do is NOTHING!

This is where something like a Serial Dev Kit Module can come in handy (see Chapter 5), because if you have built-in leds on all usable gpios then you can see what relay outputs should be doing even if you don't have any relays connected.

Likewise, don't shy away from using the freely available tools which will be introduced later, such as cicciocb's udp_debug utility, because they can add an entirely new dimension to ESP_Basic.

Right, time to dip your toes in the water and try the following script - and sure it's trivial, but it has some points to make, and sets a yardstick for things to come.

Code: Select allmemclear
print "Toolbox vers 0.1 - developed using Alpha 24"
print
wprint  "<BR><BR><BR><BR><BR>"  ' to add some blank lines
button " On " [ON]
button " Off" [OFF]
wait

[ON]
po 1 0
wait

[OFF]
po 1 1
wait


At this stage of the game it's worth considering what issues we can envisage, and take timely steps to mitigate future problems.

Two buttons is fine, but how many would be too many, and what to do then?

Web Pages
It would be handy to be able to have multiple pages of buttons, which could also neatly accomodate anything else we might accumulate. Each page would need to clear the screen and write its own contents, then likewise be over-written for all subsequent pages that get loaded.
Seeing as we are viewing everything in the browser anyway, let's use web pages as our model, and create what will effectively be our very own multi-page web server! You'll be surprised how easy ESP_Basic makes it for us to do. I can't advise you on how best to achieve things, all I can do is show you how I have learned to achieve things for myself ... it is then up to you to improve things for yourself.

It would be logical and tidy to have each page contained in it's own subroutine branch, so let's start with a 'Home' page. The first thing it needs to do is clear the screen. The next thing would be to display the page title. Then display the individual page contents (buttons or whatever). Then display some buttons to navigate the available pages. Rather than keep re-inventing the wheel for every page, we'll create a common subroutine with the navigation buttons, which we can include on every page to make life a bit easier.

Code: Select all[HOME]
cls
print "Home"  ' Title of Home page
print
html "<BR><BR><BR> " ' to add some blank lines
html "We'll add some content to this home page later<BR>"
gosub [FOOTER]

[PAGE2]
cls
print "Page 2"
print
html "<BR><BR><BR> " ' to add some blank lines
html "Number two's go here<BR>"
gosub [FOOTER]

[PAGE3]
cls
print "Page 3"
print
html "<BR><BR><BR> " ' to add some blank lines
html "Page 3 for sun readers! (Brits will know, even if they pretend not to!)<BR>"
gosub [FOOTER]

[FOOTER]
html "<BR><BR><BR>"
print
html "<BR>"
button "Home" [HOME]
button "Page2" [PAGE2]
button "Page3" [PAGE3]
html "<BR><BR>"
wait


That gives us our very own simple 3 page web server which we can add to our toolbox. I've purposely kept it separate and minimal for the moment so it can be easily used as a base for anything else anyone way wish to do for themselves. Obviously it can be expanded to as many pages as needed, with whatever page titles are wished, and with whatever contents may be required on each of the pages.

Check it out, and note that the common [FOOTER] has the one and only 'WAIT' instruction which 'paints' all of the browser screen contents for any of the pages. Any goto's that any of the pages branch to will effectively be gosubs which return them to [HOME] to 'WAIT' for the navigation buttons in the footer.

This will be better understood by placing some On and Off buttons on a page. The buttons must branch to their individual ON and OFF gosub subroutines, but then must subsequently return to the ON OFF button page to then drop down to 'wait' in FOOTER for subsequent button activations. We'll also add a convenient Toggle button. We could just leave it like that, but it offers no way of telling from the browser what the toggled button state is, so it would be handy to use our convenient method of re-writing a page of content to the browser screen to re-write changed data back to the browser to offer remote feedback indication. Then we can display different information depending on the current state of an led or relay pin for example.

So now it's time to introduce something that is easy to understand when you know, but hard to guess if you don't know, therefore you may want to pay a bit of extra attention...
Last edited by Electroguard on Mon May 30, 2016 11:20 am, edited 1 time in total.
User avatar
By Electroguard
#46960 ESP_Basic Driving Lessons - Chapter 7.

Relay
ESP_Basic uses 0 as a gpio 'On' and 1 as a gpio 'Off', which is the opposite to the 1 and 0 On/Off markings you would expect to find on a switch or appliance.
That's because an ESP's gpio's would normally ground an LED which is supplied by VCC, so the gpio pin is taken 'Low' to turn the LED 'On'. Therefore the LED is normally 'Active Low'.
A relay usually requires more current to operate than an LED so is often driven via a transistor, which doesn't need much 'base' current to switch typically 100 times more 'collector' current for driving the relay coil, but when in that configuration the transistor acts as an inverter (inverting the logic), therefore although the relay itself is active low, the transistor input requires a High voltage on its 'base' in order to switch On the relay... so the transistorised relay is effectively 'Active High'.

It's easy enough to know what gpio levels are needed to turn On or Off either active highs or active lows, but it gets very complicated trying to keep track of what's required to cause a change of state when toggling them. Rather than using different variables that require constant updating and keeping in sync, I use a much more economical method that is perhaps not intuitive and therefore needs a quick explanation, but is worth knowing.

To keep things relevent, we will assume the very cheap and readily available Sonoff mains switching relay module (which I will be coming back to shortly), but the same applies to whatever switched relay module you care to use, including any 'home brew' creations.
At the start of your script you define your LED and relay gpio pins, and also whether they are active high or active low by defining their default Off states. That is eazy-peazy, and allows simple configuration for all combinations which you might need to cater for - which in our Sonoff example requires an active high relay on pin 12, and an active low LED on pin 13.

let relaypin = 12
let ledpin = 13
let relaylogic = 0 'Relay pin is active high, so its default Off state is Low
let ledlogic = 1 'LED pin is active low, so its default Off state is High

We want the LED to 'echo' the relay state and act as a Relay indicator, and we therefore need them both to initialise to Off, so we use our defined 'logics' as their Off states.

io(po,relaypin,relaylogic) ' turns the active high relay Off as defined by the relaylogic
io(po,ledpin,ledlogic) ' turns the active low led Off as defined by the ledlogic

Once you understand the concept of using their relative 'logics' as their Off states - irrespective of absolute highs or lows or whether active high or active low - then you can use the logics to similarly discover their states at any time just by doing an appropriate compare with the logic, ie...

if io(laststat,relaypin) == relaylogic then wprint "Relay is Off" else wprint "Relay is On"
and similarly...
if io(laststat,ledpin) == ledlogic then wprint "LED is Off" else wprint "LED is On"

So now that you know what the code is doing, we can add it into the script without causing confusion. Combining things together, our Toolbox will now aquire different methods of controlling a relay, and availability of multiple web pages which allows us to offer a Help page, plus a Configuration page which will include an option to save changes to non-volatile memory for automatic re-reading at the next restart or power-up.
We may not have much configuration info to save at the moment, but that will soon change - so in a moment when you check out the next script you should pay particular attention to how we avoid overwriting configuration defaults with any un-saved optional empty read variables. You should also be aware for future reference that numeric variables are saved and read back from file i/o as text variables - so 'writing' a numeric variable called mynumber with a numeric value of 123 will cause you problems when 'reading' it back to the same mynumber variable which will then be changed into a text variable and have the text value of "123", and therefore subsequently cause invalid variable 'type' errors.
The only way around it at the moment with Alpha24 is to convert your numeric variables into text variables for writing and reading, which works ok, but means you require 2 lots of variable names for each numeric variable you wish to use and save to memory. On the plus side, writing and reading variable length text info into non-volatile memory is an absolute doddle.

We have also introduced a hardware pin interrupt into our toolkit, offering the facility to locally toggle the relay using the gpio0 flashing button. ESP_Basic makes the daunting subject of hardware interrupts very easy to use - you just need to be aware that both rising and falling interrupts are generated (will be dealt with later), and that software pullups are not currently available so a hardware pullup resistor (typically about 10K) may need to be added (the Sonoff module already contains a hardware pullup resistor, but the Ser Dev Kit module does not).

Sonoff Module
The Sonoff is a ready-built low-cost ESP-8266-based small switched-mains module available from places like ebay for about £6. It has some issues you need to be aware of, but it is cheap and convenient and readily hackable, and the issues are not any worse than you would face if making your own home-brew equivalent.

There is a Sonoff version available which includes an RF remote control capability, but for the purposes of this tutorial I am going to be assuming the basic non-RF version.

The relay is single-pole, so for obvious safety reasons you should ensure that the relay switches the live rather than the neutral, else everything live will remain permanently live.
Also for obvious safety reasons it is advisable to connect up a pass-through earth wire between the mains input and switched mains output.
Pay attention to the marked mains input and mains output directions because they are not bi-directional.
Although the relay is rated at 10Amps, I would not recommend switching 10A loads via the soldered pcb tracks which have to carry that mains current - if you wish to control high currents for heaters etc, better to use the Sonoff just to switch an external higher current double-pole mains relay.
IMPORTANT - The Sonoff onboard 3.3v supply is derived from the mains, and could be at mains potential, so you are strongly advised against making any physical non-mains connection to the Sonoff while it is connected to the mains. YOU HAVE BEEN WARNED.

Flashing Pins hack.
The first thing to do is solder pins into the vacant 4 or 5 0.1" pitch holes which connect to 3.3v, RX, TX, GND (and in the newer 5 hole versions, gpio14).
This will then allow connecting the unit to an external 3.3v supply and a uart for flashing.
One of the great advantages of ESP_Basic of course, is that once flashed, all subsequent programming is non-contact OTA using wifi.

The onboard gpio00 button can be used to enter flashing mode at bootup. It already has a pullup resistor, so can also be used for user input during normal operation. The relay is driven by gpio12 and is active high. The green side of the bi-colour led connects to gpio13 and is active low. I believe the red side connects to the optional RF module, but it's not something we need to bother with.
If you have a recent version it will have a 5th pin hole which is connected to gpio14 and can be used to connect a DHT temperature and humidity sensor if wished, and details will be given later for turning the Sonoff into a temperature or humidity stat.

Button hack.
It is possible to do a button hack to extend the buttons pins out via a pair of wires to an external button. As previously mentioned, the following code allows use of the onboard button to locally toggle the relay if required.
So if you think about that, it is quite feasible to use a wall switch connected to the Sonoff by low voltage extended button wires to control mains room lighting, and of course along with the already existing capability of also controlling the room lighting via tablet or mobile wifi connection (and possibly also by RF remote control if you have the RF version!). By default the wall switch would need to be a momentary press switch, but you are in control of sensing the 'press' and 'release' interrupts, so you could modify for normal on/off switch operation if wished.

The Sonoff is claimed to work from 90 to 250 V AC - so for less than a tenner per switch you could convert all your room lighting to wifi and/or RF remote control no matter wherever you live in the world... now that's got to be better than a kick up the bum, init!

5v hack.
Suppose you want the relay to switch some other voltage instead of the mains. The problem is that the onboard 5v supply is taken from the mains tracks on the pcb, so if you do not supply the Sonoff with mains you will not have the onboard 5v supply to power the electronics.
There is a 5v hack that lets you supply the board with 5v from an external supply (eg: USB) across diode D5 on the underside of the pcb, which therefore allows you to use the relay switched contacts for low voltages other than mains.
Or you could similarly supply external 3.3v to the flashing pins, and the relay will still operate ok (mine does anyway). The alternative would be to use the unhacked switched mains to operate an external mains relay and use those contacts for low volts use.

Relay Control code

Code: Select all'SonOff example
memclear
let ledpin = 13
let ledlogic = 1  ' Default led pin off state
let relaypin = 12
let relaylogic = 0  ' Default relay pin off state
io(po,ledpin,ledlogic)
io(po,relaypin,relaylogic)
let localbutton = 0  ' Uses onboard GOIO00 flashing button by default, change to suit.
interrupt localbutton [PRESSED]  ' Interrupt pin requires a pull-up resistor to work.
gosub [READVARS]
if name == "" then let name = "Electroguard"
if description == "" then let description = "Switched Mains Relay - version 1"
let esp_basic = " - Developed on Alpha 24"

[HOME]
cls
print " "
button " ? " [HELP]
wprint " "
wprint name & " " & description & esp_basic
print " "
wprint "<BR><BR><BR>"
if io(laststat,relaypin) == relaylogic then wprint "Relay is OFF" else wprint "Relay is ON"
wprint "<BR><BR><BR>"
button "On" [RELAYON]
button "toggle" [TOGGLE]
button "Off" [RELAYOFF]
wprint "<BR><BR><BR>"
button "Configuration" [CONFIG]
wait

[HELP]
cls
print " "
button "X" [HOME]
wprint "   "
wprint name & " " & description & esp_basic
print " "
wprint "<BR>"
wprint "<BR><BR>"
wprint "On, Off and Toggle switching of relay"
wprint "<BR><BR>"
wprint "Also offers local hardware button toggle of relay."
wprint "<BR><BR>"
wprint "Configuration options allow changing of title Name and Description."
wprint "<BR><BR>"
wprint "Home button changes are temporary, Save button changes are permanent to non-volatile flash memory."
wprint "<BR><BR>"
wprint "This script is configured for a Sonoff module, but should be adaptable for any alternative "
wprint "switched relay modules."
wprint "<BR><BR>"
wprint "Sonoff pins - button=0, led=12, relay=13. "
wprint "<BR>"
wprint "Sonoff relay is active high, so relaylogic=0 (OFF default=0)."
wprint "<BR>"
wprint "Ledlogic=1 (active low),"
wprint "<BR>"
wprint "<BR><BR>"
button "Home" [HOME]
wait

[CONFIG]
cls
print " "
button "X" [HOME]
wprint " "
wprint name & " " & description & esp_basic
print " "
wprint "<BR><BR>"
html "Name:  "
textbox name
wprint " "
html "Description:  "
textbox description
'html "<BR><BR>"
wprint "<BR><BR><BR>"
button "Home" [HOME] ' don't save edits
wprint " "
button "Save" [SAVE] ' save details to persistent memory
wprint " "
wprint "HOME loses changes at power-off, SAVE holds changes in non-volatile flash memory. "
wprint "<BR><BR>"
wait

[READVARS]
read Name name  ' "Name" = flash memory var name, "name" = ESP_Basic var name
read Description description
return

[SAVE]
write Name name
write Description description
goto [HOME]

[RELAYON]
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 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]

[TOGGLE]
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]

[PRESSED]
if io(laststat,localbutton) = 0 then goto [TOGGLE] ' (toggles only on button press instead of on button release)
goto [HOME]


This gives you several things to check out and be comfortable with - try temporarily changing info in the configuration, then exiting and restarting the program, then do likewise after permanently saving changes to non-voltaile memory. Be aware that there are currently no housekeeping file commands in Alpha 24, so whatever variables you create will stick with you like a fart in a spacesuit until you do a reformat and reflash of the wee beastie.

Note also how responsive the actual relay and led changes are, even though there may be some slight lag in the browser status being updated.

Don't forget to try toggling the relay with the gpio00 hardware button.
Note that the script is looking for just the button presses and not toggling on the releases, otherwise it would act like a momentary switch just while the button is held down... which perhaps may be the sort of behaviour you might need for some future project. Something else you may want to consider for the future is that if you change the interrupt to only act on the release (instead of the press), it would allow you to time how long the button was pressed down and enable you to take different actions for long or short presses if you wished... ie a short press could toggle the relay, whereas a long press might blink the IP address on the led. But we are getting ahead of ourselves, because different actions are something which can be selected and saved as default behaviour using a configuration setting if wished.
Last edited by Electroguard on Mon May 30, 2016 5:08 pm, edited 2 times in total.
User avatar
By Electroguard
#46961 ESP_Basic Driving Lessons - Chapter 8

This project was developed around the readily available Sonoff relay module, which in the absence of any info to the contrary is assumed to be a 512K device and therefore unsuitable for ESP_Basic 3.
It was originally intended as the central component of a planned UDP automation and control system which would have included Speech Announcement module, Infra-red module, PIR Trigger modules etc etc, and been the culminating chapters of the Driving Lessons tutorials. But ESP_Basic 3 has moved on and left it behind before it was born, so rather than completely waste all the development time and effort it is now being offered as just a useful ESP_Basic 2 Alpha 24 switched mains relay module.

Although developed by default for the Sonoff, the software is fully configurable and should be suitable for any other ESP-based switched relay units, including home-brews. Configuration changes can be saved to non-volatile memory and therefore retained through power-off reboots.

It has an extensive feature list which includes web control, UDP network control, normally On, normally Off, Toggle, delayed On and Off timers, On and Off duration timers, Temperature or Humidity Stat, and more.

As a UDP network node it can be remotely controlled by other network nodes such as PIR triggers etc (or cicciocb's UDP utility of course), and incorporates various additional network access features such as BlinkIP.

Commands and facilities are listed on an integrated Help page.

The script is an evolutionary collection of 'proofs of concept' which would have been re-written and optimised when completed, but unfortunately was made obsolete before a trivial 'button-size' issue was resolved. The intention was to make everything accessible on an initial 'busy' Home page, and with the option to configure a chosen more basic start mode for an uncluttered Big Button User startup page which was easier to use with small-screen mobiles etc - but the user startup pages would still need smaller Config button access to be able to reconfigure whenever required.
Probably a trifling matter to resolve for someone with a bit of webby experience, and possibly considered a minor cosmetic inconsequence for others, but actually quite an important requirement for remote control of automation systems using small-screen mobiles and tablets etc. Anyway, it's irrelevent now, but I have not deleted the corresponding UserPages in case anyone wants to belatedly implement something similar for their own purposes. They can be accessed from Config, then clicking the Start mode dropbox - UserToggle is a large button example, and UserOnOff is the equivalent small Config ! button example. After selecting, click Home to see the temporary result.

The same 'Start mode' dropbox allows selecting 'normally On' startup mode, which can be made permanent by clicking the Save button. Use this if you require to provide a remote reboot facility to routers or servers etc... you would boot the relay node to 'normally On', then choose CycleOff with an appropriate Off duration to reboot any connected devices - the relay would switch off for the specified duration, then switch back on again. Such reboot instructions could be issued automatically by a node losing internet connection if wished.

The CycleOn instruction might be issued by PIR sensors activated by peoples movements to automatically turn On lighting for a predetermined time - set 'Start mode' to 'normally Off'.

The 'FlipSwitch' option in the 'Local button mode' dropbox allows configuring for a locally attached standard 'flip' type lightswitch (in parallel with the momentary flashing button), enabling the unit to be used for automated control of standard household lighting circuits... the Sonoff would be installed in the roof space driving the lamp via its relay, and a couple of wires in parallel with the Sonoffs flashing button would be taken down to the light switch which must obviously no longer be connected to the mains!

Sonoff Hack
If you open up a Sonoff module you will see a row of 4 or 5 pin holes in line with the button.
Solder header pins into these vacant holes. Counting from the button, the pin connections are 3.3v, RX, TX, GND, and if you have a later version with a 5th hole, it is gpio14.
If you wish to use an external button (ie: for the 'FlipSwitch' option above), solder a pair of thin wires to the 2 outside button contacts.
Once you have the holes populated with pins you can flash the Sonoff with ESP_Basic 2 Alpha 24 (the final V2 release version).
CAUTION - DO NOT POWER THE SONOFF FROM THE MAINS WHILE FLASHING!
Power the Sonoff by taking a 3.3v supply direct to the pin nearest the button and 0v to the 4th GND pin. Apply power while holding down the button to put the ESP into flash mode, then format and flash as normal. You can do any testing and development and debugging by powering in the same manner, so you only ever need to connect the Sonoff up to the Mains once it is reassembled and ready for use.
IMPORTANT - do not let the future of you or your family or your pets or your possessions depend on the Sonoff hardware! The onboard relay is single-pole, so ensure you switch the potentially lethal LIVE rather than the relatively safe neutral. Just because the relay is rated at 10 amps does not mean that the Sonoff pcb tracks which have to take the current are also rated at 10 amps - if you want to switch high current Mains, use the Sonoff to switch an external Mains relay, preferably double-pole. The Sonoff has no earth connections, so provide a pass-through earth from your incoming Mains to your switched appliance(s).
Those same observations apply equally to any home-brew switched-mains relay units, or any other bought units for that matter - so try to remember that the only person you can trust to have a vested interest in your safety and future and who is NOT trying to make money out of you... is YOU!

If you have the later version Sonoff with gpio14, or a home-brew module with a spare gpio, you can use the spare gpio as input for a DHT temperature and humidity sensor.
To use the unit as a thermo 'Stat' or humidity 'Stat', select Stat from the 'Start mode' dropdown in Config, select an appropriate model from the DHT sensor dropdown (11,21,22), then select a required mode (TooHot, TooCold, TooWet, TooDry) from the Stat mode dropdown... Too Hot turns the relay on Above the temperature setting to drive a cooling fan, Too Cold turns the relay on Below the temp setting to drive a heater, Too Wet turns the relay on Above the humidity setting to drive a ventilation fan, Too Dry turns the relay on Below the humidity setting to drive a 'mister' or irrigation pump etc.
These options were only intended as working proof of concept, so if you wish to use 'Stat' mode in a real-world application you might want to consider increasing reliability by only changing relay state after taking several consecutive similarly changed readings to average out any inconsistencies. In particular, the DHT11 humidity readings can be very variable, and in reality the DHT11 is not a preferred choice because it is significantly less accurate than the DHT22 and cannot give temperature readings below freezing.
The default timer frequency is 5 secs between sensor readings, but you can change thr value of 'frequency' in the sketch if you wish. Obviously you cannot send relay On/Off instructions to the module when it is being used in Stat mode because they will be over-ridden by the frequently updated Stat control logic, so if you wish to manually over-ride Stat mode you need to disable the timer. I've noticed a couple of 'quirks'... when the timer updates the DHT readings, the new reading is not updated on screen, and doing a browser refresh to update the screen reading seems to cause a repeat of the last used up or down button counter - but it doesn't prevent the Stat modes from working, and because ESP_Basic 2 and the project are already history I have no incentive to waste any more time or effort by pointlessly looking any deeper. That does not detract from the projects usefulness though, and hopefully it will still be appreciated

Code: Select all'SonOff Relay Module
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]  ' Will require pull-up resistor to work.
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 = "Electroguard Relay Module - Sonoff version 1 "
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

[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


[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) else let numblinks = 6
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" 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 udpreply localname &  " Local button pressed"
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

Last edited by Electroguard on Sat Aug 06, 2016 7:09 am, edited 2 times in total.