Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter...
Transcript of Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter...
![Page 1: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/1.jpg)
ABeginner'sGuidetotheESP8266PieterP, 08-03-2017
Sometimeago,IwroteaBeginner'sGuidetoArduinothatseemstobeverypopular,soIdecidedtocreateafollow-up:ABeginner'sGuidetotheESP8266.That'sright,atutorialonhowtousetheworld'smostpopular$3Wi-Fiboard.
Thisisgoingtobeaveryin-depthtutorial,coveringsomenetworkingconceptsaswell.Ifyou'reabeginner,andjustwanttogostraighttothemoreexcitingWi-Fipart,feelfreetodoso,IincludedshortTL;DR'sinthelonger,moretechnicalparts.
AshortoverviewofwhatI'llcoverinthisarticle:
1. WhatisanESP8266?AshortoverviewofwhatanESP8266is,andwhatyoucandowithit2. Decidingonwhatboardtobuy:There'sloadsofdifferentESP8266availablethesedays,findingtheonethat'sbestforyou
canbehard3. Installingthesoftware:youneedtoinstallsomesoftwaretoprogramtheESP8266,andmaybeaUSBdriver4. Settingupthehardware:somemodulesandboardsneedsomeexternalcomponents5. TheESP8266asamicrocontroller:theESP8266canbeusedasanormalmicrocontroller,justlikeanArduino6. Networkprotocols:BeforewestartusingtheWi-FicapabilitiesoftheESP8266,I'llteachyousomeofthenetworkprotocols
involved7. SettingupaWi-Ficonnection:That'sprobablywhyyou'rereadingthis,right?8. Nameresolution:FindtheESP8266onyourlocalnetworkusingmDNS9. Settingupasimplewebserver:ThisenablesyoutoaddwebpagestotheESP8266,andbrowsethemfromyourcomputeror
phone10. Settingupanadvancedwebserver:amoreadvancedserverwitharealfilesystemthatallowsyoutouploadnewfilesover
Wi-Fi11. OTA-uploadingprogramsoverWi-Fi:Youdon'thavetouploadprogramsoverUSB,youcanuseWi-Fiinstead12. WirelesslycontrollingyourRGBlighting:ChangethecolorofyourLEDstripsusingyourphoneorcomputer13. Gettingthetime:ConnecttoatimeserverusingNTPandsynctheESP'sclock14. Monitoringsensors:logthetemperatureinyourlivingroom,saveitinflashmemoryandshowitinafancygraphinyour
browser15. Gettingemailnotifications:Turnonanotificationlightwhenyou'vegotunreademails16. Advancedfeatures:useDNS,captiveportals,Wi-Ficonnectorlibraries,OSC...
ThisguideexpectssomebasicknowledgeofmicrocontrollersliketheArduino.Ifthat'ssomethingyou'renotalreadyfamiliarwith,I'drecommendyoutoreadmyBeginner'sGuidetoArduinofirst,itcoversalotofthebasicsthatIwon'tgointointhisarticle.IreallywanttofocusontheESP8266-specificthings,likeWi-Fiandothernetworkprotocols,theESP'shardware,software,IoT,etc...
WhatisanESP8266?TheESP8266isaSystemonaChip(SoC),manufacturedbytheChinesecompanyEspressif.ItconsistsofaTensilicaL10632-bitmicrocontrollerunit(MCU)andaWi-Fitransceiver.Ithas11GPIOpins*(GeneralPurposeInput/Outputpins),andananaloginputaswell.ThismeansthatyoucanprogramitlikeanynormalArduinoorothermicrocontroller.Andontopofthat,yougetWi-Ficommunication,soyoucanuseittoconnecttoyourWi-Finetwork,connecttotheInternet,hostawebserverwithrealwebpages,letyoursmartphoneconnecttoit,etc...Thepossibilitiesareendless!It'snowonderthatthischiphasbecomethemostpopularIOTdeviceavailable.
Therearemanydifferentmodulesavailable,standalonemodulesliketheESP-##seriesbyAIThinker,orcompletedevelopmentboardsliketheNodeMCUDevKitortheWeMosD1.Differentboardsmayhavedifferentpinsbrokenout,havedifferentWi-Fiantennas,oradifferentamountofflashmemoryonboard.
(*)TheESP8266chipitselfhas17GPIOpins,but6ofthesepins(6-11)areusedforcommunicationwiththeon-boardflashmemorychip.
Programming
TherearedifferentwaystoprogramtheESP8266,butI'llonlycoverthemethodusingtheArduinoIDE.Thisisreallyeasyforbeginners,andit'saveryfamiliarenvironmentifyou'veusedArduinoboardsbefore.Justkeepinmindthatit'snotlimitedtothisoption:there'salsoanofficialSDKavailabletoprogramitinrealC,thisisveryusefulifyouwanttooptimizeyourcodeordosomeadvancedtricksthataren'tsupportedbytheArduinoIDE.AnotherpossibilityistoflashitwithaLUAinterpreter,soyoucanuploadandrunLUAscripts.Ormaybeyou'remorefamiliarwithPython?ThenyoushouldcheckouttheMicroPythonfirmwaretointerpretMicroPythonscripts.I'msurethere'sotherlanguagesavailableaswell,sojustdoaquickGooglesearchandwriteyourcodeinthelanguageofyourchoice.
RequirementsYou'llneedacoupleofthingsinordertofollowthisguide:
AnESP8266boardAcomputerthatcanruntheArduinoIDE(Windows,MacorLinux)AUSB-to-Serialconverter,itisveryimportantthatyouusea3.3Vmodel*AUSBcableA3.3Vpowersupplyorvoltageregulator*AWi-Finetworktoconnectto
(*)Yourboardmayalreadyincludethese.Moreinformationcanbefoundinthenextchapter.
![Page 2: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/2.jpg)
HardwareDecidingonwhatboardtobuy
ESP8266isjustthenameofthechip,manycompanieshavedesignedtheirownboardsthatusethischip,sotherearemanydifferentESP8266boardsonthemarket.Ifyoudon'tknowthedifferencebetweenallthesedifferentmodels,youmighthaveahardtimedecidingonwhatboardtobuy.
Theeasiest(andfastest)waytogetanESP8266boardistobuyonefromawell-knownelectronicsshoplikeAdafruitorSparkFun,butifyouwantitcheap,youshouldcheckoutEbayorothersiteswhereyoucanorderthemdirectlyfromChina.
Developmentboards
Someboardshaveallkindsoffeatureson-boardtohelpdevelopingESP8266hardwareandsoftware:forexample,aUSBtoSerialconverterforprogramming,a3.3Vregulatorforpower,on-boardLEDsfordebugging,avoltagedividertoscaletheanaloginput...Ifyou'reabeginner,Iwoulddefinitelyrecommendadevelopmentboard.It'seasiertogetstartedifyoudon'thavetoworryaboutallthesethings.
Bare-bonesAIThinkerboards
IfyouwanttoaddanESP8266toasmallproject,orifyouwantacheaper*board,youmightwanttobuyaboardthatdoesn'thavethesefeatures.Inthatcase,youcanbuyoneofthemanyESP-##modulesdevelopedbyAIThinker.TheycontainjusttheESP8266andthenecessarycomponentstorunit.Toprogramtheboard,you'llneedanexternalUSB-to-Serialconverter.Withsomemodules,yougetanon-boardantenna(PCBorceramic)andanLED,someboardshavejustanantennaconnector,ornoLEDsatall.Theyalsodifferinphysicalsize,andflashmemorysize.Animportantthingtonotice,isthatsomeboardsdonotbreakoutallGPIOpins.Forexample,theESP-01onlyhas2I/Opinsavailable(apartfromtheTXandRXpins),whileothermodulesliketheESP-07orESP-12breakoutallavailableI/Opins.
(*)Theboarditselfischeaper,butyou'llhavetospendmoreonexternalparts.
Overview
Here'satablewithsomeofthemostpopularESP8266developmentboardsandtheirfeatures:
Board GPIO 3.3VVreg
USB-to-Serial
Auto-Reset
Auto-Program Flash ADC
range Extra
SparkFunESP8266Thing 11 + - + ±* 512KB(4Mb) 0-1V Batterycharger,cryptoelement,temperaturesensor,lightsensor
SparkFunESP8266Thing-DevBoard 11 + + + + 512KB(4Mb) 0-1V
NodeMCU 11 + + + + 4MB(32Mb) 0-3.3V
AdafruitFeatherHUZZAHwithESP8266 11 + + + + 4MB(32Mb) 0-1V Batterycharger
AdafruitHUZZAHESP8266Breakout 11 + - - - 4MB(32Mb) 0-1V 5V-tolerantRXandResetpins
ESP-## 4-11 - - - - 512KB(4Mb)–
4MB(32Mb) 0-1V Smallandcheap
YoucanfindthefulllistofESP-##moduleshere.
Asyoucansee,boththeNodeMCUandtheAdafruitFeatherHUZZAHaresolidchoices.
(*)Whenauto-programontheSparkFunESP8266Thingisenabled,youcan'tusetheSerialMonitor.
Gettingthehardwareready
TherearetwomaincategoriesofESP8266boards:developmentboardswithaUSBinterface(USB-to-Serialconvertor)on-board,andboardswithoutaUSBconnection.
DevelopmentboardswithaUSBinterface
Forexample:NodeMCU,SparkFunESP8266Thing-DevBoard,SparkFunBlynkBoard,AdafruitFeatherHUZZAHwithESP8266Wi-Fi...
TheseboardswillshowupinDevicemanager(Windows)orinlsusb(Linux)assoonasyouplugthemin.Theyhavea3.3Vregulatoron-board,andcanbeprogrammedoverUSBdirectly,soyoudon'tneedanyexternalcomponentstogetitworking.Theonlythingyoumayneedtodo,issolderonsomeheaders.
Bare-bonesboardsandboardswithoutaUSBinterface
Thiscategoryhas2sub-categories:boardswitha3.3Vregulatoron-board,andboardswithjusttheESP8266andaflashmemorychip,without3.3Vregulator.Ifyourboarddoesn'thavea5Vto3.3Vregulator,buyoneseparately.YoucoulduseanLM1117-3.3forexample.Theon-board3.3VregulatorofmostArduinoboardsisnotpowerfulenoughtopowertheESP.
Toprogramtheboard,you'llneedaUSB-to-Serialconverter.TheFTDIFT232RLisquitepopular,becauseitcanswitchbetween5Vand3.3V.ItisessentialthattheUSB-to-Serialconverteryoubuyoperatesat3.3V.Ifyoubuya5Vmodel,youwilldamagetheESP8266.
ConnectingtheUSB-to-Serialconverter
![Page 3: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/3.jpg)
1. Connecttheground(GND)oftheUSB-to-SerialconvertertothegroundoftheESP8266.2. ConnecttheRX-pinoftheUSB-to-SerialconvertertotheTXDpinoftheESP8266.(Onsomeboards,it'slabelledTXinsteadof
TXD,butit'sthesamepin.)3. ConnecttheTX-pinoftheUSB-to-SerialconvertertotheRXDpinoftheESP8266.(Onsomeboards,it'slabelledRXinsteadof
RXD,butit'sthesamepin.)4. IfyourESP8266boardhasaDTRpin,connectittotheDTRpinoftheUSB-to-Serialconverter.Thisenablesauto-resetwhen
uploadingasketch,moreonthatlater.
Enablingthechip
Ifyou'reusingabare-boneESP-##boardbyAIThinker,youhavetoaddsomeresistorstoturnontheESP8266,andtoselecttherightbootmode.
1. EnablethechipbyconnectingtheCH_PD(ChipPowerDown,sometimeslabeledCH_ENorchipenable)pintoVCCthrougha10KΩresistor.
2. DisableSD-cardbootbyconnectingGPIO15togroundthrougha10KΩresistor.3. SelectnormalbootmodebyconnectingGPIO0toVCCthrougha10KΩresistor.4. PreventrandomresetsbyconnectingtheRST(reset)pintoVCCthrougha10KΩresistor.5. Makesureyoudon'thaveanythingconnectedtoGPIO2(moreinformationinthenextchapter).
Addingresetandprogrambuttons
IfyourESP8266boarddoesn'thavearesetbutton,youcouldaddonebyconnectingapushbuttontobetweentheRSTpinandground.
Toputthechipintoprogrammingmode,youhavetopullGPIO0lowduringstartup.That'swhywealsoneedaprogrambutton.Becauseit'spossibletouseGPIO0asanoutput,wecan'tdirectlyshortittoground,thatcoulddamagethechip.Topreventthis,connect470Ωresistorinserieswiththeswitch.It'simportantthatthisresistanceislowenough,otherwise,itwillbepulledhighbythe10KΩresistorweaddedinthepreviousparagraph.
Connectingthepowersupply
IftheESP8266moduleyouhavedoesn'thavea3.3Vvoltageregulatoronboard,youhavetoaddoneexternally.YoucoulduseanLM1117-3.3forexample.
1. Connectthefirstpinoftheregulatortoground.2. Placea10µFcapacitorbetweenpin2(Vout)andground.Watchthepolarity!3. Placea10µFcapacitorbetweenpin3(Vin)andground.4. Connectpin2tothe3.3VorVCCoftheESP8266.5. Connectpin3toa5Vpowersource,aUSBport,forexample.
![Page 4: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/4.jpg)
![Page 5: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/5.jpg)
Beforeyoubegin...There'safewthingsyouhavetolookoutforwhenusinganESP8266:Themostimportantthingisthatitrunsat3.3V,soifyouconnectittoa5Vpowersupply,you'llkillit.Unlikesome3.3VArduinoorTeensyboards,theESP8266'sI/Opinsarenot5Vtolerant,soifyouusea5VUSB-to-Serialconverter,or5Vsensorsetc.you'llblowitup.AsecondthingtokeepinmindisthattheESP8266canonlysourceorsink12mAperoutputpin,comparedto20-40mAformostArduinos.TheESP8266hasoneanalogtodigitalconverter,butithasastrangevoltagerange:0-1V,voltagesabove1Vmightdamagetheboard.
OnelastthingtokeepinmindisthattheESP8266hastosharethesystemresourcesandCPUtimebetweenyoursketchandtheWi-Fidriver.Also,featureslikePWM,interruptsorI²Careemulatedinsoftware,mostArduinosontheotherhand,havededicatedhardwarepartsforthesetasks.Formostapplicationshowever,thisisnottoomuchofanissue.
![Page 6: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/6.jpg)
SoftwareInstallationoftherequiredsoftware
ThefirststepistodownloadandinstalltheArduinoIDE.IexplainedthisinABeginner'sGuidetoArduino.(AsofFebruary7th2017,thelateststableversionoftheIDEis1.8.1.)
ToprogramtheESP8266,you'llneedapluginfortheArduinoIDE,itcanbedownloadedfromGitHubmanually,butitiseasiertojustaddtheURLintheArduinoIDE:
1. OpentheArduinoIDE.2. GotoFile>Preferences.3. PastetheURLhttp://arduino.esp8266.com/stable/package_esp8266com_index.jsonintotheAdditionalBoardManagerURLsfield.
(YoucanaddmultipleURLs,separatingthemwithcommas.)4. GotoTools>Board>BoardManagerandsearchfor'esp8266'.Selectthenewestversion,andclickinstall.(AsofFebruary7th
2017,thelateststableversionis2.3.0.)
Youcancheckouttheofficialinstallguidehere.
Drivers
IfyouareusingaboardwiththeCH340(G)USB-to-Serialchip,liketheNodeMCU,you'llprobablyhavetoinstalltheUSBdriversforit.TheycanbefoundonGitHub.IfyouareusingaboardwiththeCP2104USB-to-Serialchip,liketheAdafruitFeatherHUZZAHboard,you'llprobablyhavetoinstallUSBdriversaswell.YoucanfindthemontheSiliconLabswebsite.BoardswithanFTDIchipshouldworkrightoutofthebox,withouttheneedofinstallinganydrivers.
Python
IfyouwanttouseOverTheAirupdatesonWindows,youhavetoinstallPython2.7.Youcandownloaditfrompython.org.Duringtheinstallation,youhavetoselecttheoptiontoaddPythontoyourpath.Ifyoudon'tdothis,theArduinoIDEwon'tbeabletofindthePythonexecutable.
Examples
YoucanfindallexamplesusedinthisarticleonmyGitHub.Justdownloaditasa.ZIPfile,unzipittoaconvenientlocation,andyou'regoodtogo!
![Page 7: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/7.jpg)
TheESP8266asamicrocontroller-HardwareWhiletheESP8266isoftenusedasa‘dumb’Serial-to-WiFibridge,it’saverypowerfulmicrocontrolleronitsown.Inthischapter,we’lllookatthenon-Wi-FispecificfunctionsoftheESP8266.
DigitalI/OJustlikeanormalArduino,theESP8266hasdigitalinput/outputpins(I/OorGPIO,GeneralPurposeInput/Outputpins).Asthenameimplies,theycanbeusedasdigitalinputstoreadadigitalvoltage,orasdigitaloutputstooutputeither0V(sinkcurrent)or3.3V(sourcecurrent).
Voltageandcurrentrestrictions
TheESP8266isa3.3Vmicrocontroller,soitsI/Ooperatesat3.3Vaswell.Thepinsarenot5Vtolerant,applyingmorethan3.6Vonanypinwillkillthechip.
ThemaximumcurrentthatcanbedrawnfromasingleGPIOpinis12mA.
Usablepins
TheESP8266has17GPIOpins(0-16),however,youcanonlyuse11ofthem,because6pins(GPIO6-11)areusedtoconnecttheflashmemorychip.Thisisthesmall8-leggedchiprightnexttotheESP8266.Ifyoutrytouseoneofthesepins,youmightcrashyourprogram.
GPIO1and3areusedasTXandRXofthehardwareSerialport(UART),soinmostcases,youcan’tusethemasnormalI/Owhilesending/receivingserialdata.
Bootmodes
Asmentionedinthepreviouschapter,someI/Opinshaveaspecialfunctionduringboot:Theyselect1of3bootmodes:
GPIO15 GPIO0 GPIO2 Mode0V 0V 3.3V UartBootloader0V 3.3V 3.3V Bootsketch(SPIflash)3.3V x x SDIOmode(notusedforArduino)
Note:youdon’thavetoaddanexternalpull-upresistortoGPIO2,theinternaloneisenabledatboot.
Wemadesurethattheseconditionsaremetbyaddingexternalresistorsinthepreviouschapter,ortheboardmanufacturerofyourboardaddedthemforyou.Thishassomeimplications,however:
GPIO15isalwayspulledlow,soyoucan’tusetheinternalpull-upresistor.YouhavetokeepthisinmindwhenusingGPIO15asaninputtoreadaswitchorconnectittoadevicewithanopen-collector(oropen-drain)output,likeI²C.GPIO0ispulledhighduringnormaloperation,soyoucan’tuseitasaHi-Zinput.GPIO2can’tbelowatboot,soyoucan’tconnectaswitchtoit.
Internalpull-up/-downresistors
GPIO0-15allhaveabuilt-inpull-upresistor,justlikeinanArduino.GPIO16hasabuilt-inpull-downresistor.
PWM
UnlikemostAtmelchips(Arduino),theESP8266doesn’tsupporthardwarePWM,however,softwarePWMissupportedonalldigitalpins.ThedefaultPWMrangeis10-bits@1kHz,butthiscanbechanged(upto>14-bit@1kHz).
AnaloginputTheESP8266hasasingleanaloginput,withaninputrangeof0-1.0V.Ifyousupply3.3V,forexample,youwilldamagethechip.SomeboardsliketheNodeMCUhaveanon-boardresistivevoltagedivider,togetaneasier0-3.3Vrange.Youcouldalsojustuseatrimpotasavoltagedivider.
TheADC(analogtodigitalconverter)hasaresolutionof10bits.
Communication
Serial
TheESP8266hastwohardwareUARTS(Serialports):UART0onpins1and3(TX0andRX0resp.),andUART1onpins2and8(TX1andRX1resp.),however,GPIO8isusedtoconnecttheflashchip.ThismeansthatUART1canonlytransmitdata.
UART0alsohashardwareflowcontrolonpins15and13(RTS0andCTS0resp.).ThesetwopinscanalsobeusedasalternativeTX0andRX0pins.
I²C
TheESPdoesn’thaveahardwareTWI(TwoWireInterface),butitisimplementedinsoftware.Thismeansthatyoucanuseprettymuchanytwodigitalpins.Bydefault,theI²Clibraryusespin4asSDAandpin5asSCL.(ThedatasheetspecifiesGPIO2asSDAandGPIO14asSCL.)Themaximumspeedisapproximately450kHz.
SPI
![Page 8: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/8.jpg)
TheESP8266hasoneSPIconnectionavailabletotheuser,referredtoasHSPI.ItusesGPIO14asCLK,12asMISO,13asMOSIand15asSlaveSelect(SS).ItcanbeusedinbothSlaveandMastermode(insoftware).
GPIOoverview
GPIO Function State Restrictions0 Bootmodeselect 3.3V NoHi-Z1 TX0 - NotusableduringSerialtransmission
2 BootmodeselectTX1 3.3V(bootonly) Don’tconnecttogroundatboottime
Sendsdebugdataatboottime3 RX0 - NotusableduringSerialtransmission4 SDA(I²C) - -5 SCL(I²C) - -6-11 Flashconnection x Notusable,andnotbrokenout12 MISO(SPI) - -13 MOSI(SPI) - -14 SCK(SPI) - -15 SS(SPI) 0V Pull-upresistornotusable
16 Wakeupfromsleep - Nopull-upresistor,butpull-downinsteadShouldbeconnectedtoRSTtowakeup
TheESP8266asamicrocontroller-SoftwareMostofthemicrocontrollerfunctionalityoftheESPusesexactlythesamesyntaxasanormalArduino,makingitreallyeasytogetstarted.
DigitalI/O
JustlikewitharegularArduino,youcansetthefunctionofapinusingpinMode(pin,mode);wherepinistheGPIOnumber*,andmodecanbeeitherINPUT,whichisthedefault,OUTPUT,orINPUT_PULLUPtoenablethebuilt-inpull-upresistorsforGPIO0-15.Toenablethepull-downresistorforGPIO16,youhavetouseINPUT_PULLDOWN_16.
(*)NodeMCUusesadifferentpinmapping,readmorehere.ToaddressaNodeMCUpin,e.g.pin5,useD5:forinstance:pinMode(D5,OUTPUT);
Tosetanoutputpinhigh(3.3V)orlow(0V),usedigitalWrite(pin,value);wherepinisthedigitalpin,andvalueeither1or0(orHIGHandLOW).
Toreadaninput,usedigitalRead(pin);
ToenablePWMonacertainpin,useanalogWrite(pin,value);wherepinisthedigitalpin,andvalueanumberbetween0and1023.
Youcanchangetherange(bitdepth)ofthePWMoutputbyusinganalogWriteRange(new_range);
ThefrequencycanbechangedbyusinganalogWriteFreq(new_frequency);.new_frequencyshouldbebetween100and1000Hz.
Analoginput
JustlikeonanArduino,youcanuseanalogRead(A0)togettheanalogvoltageontheanaloginput.(0=0V,1023=1.0V).
TheESPcanalsousetheADCtomeasurethesupplyvoltage(VCC).Todothis,includeADC_MODE(ADC_VCC);atthetopofyoursketch,anduseESP.getVcc();toactuallygetthevoltage.Ifyouuseittoreadthesupplyvoltage,youcan’tconnectanythingelsetotheanalogpin.
Communication
Serialcommunication
TouseUART0(TX=GPIO1,RX=GPIO3),youcanusetheSerialobject,justlikeonanArduino:Serial.begin(baud).
Tousethealternativepins(TX=GPIO15,RX=GPIO13),useSerial.swap()afterSerial.begin.
TouseUART1(TX=GPIO2),usetheSerial1object.
AllArduinoStreamfunctions,likeread,write,print,println,...aresupportedaswell.
I²CandSPI
YoucanjustusethedefaultArduinolibrarysyntax,likeyounormallywould.
SharingCPUtimewiththeRFpartOnethingtokeepinmindwhilewritingprogramsfortheESP8266isthatyoursketchhastoshareresources(CPUtimeandmemory)withtheWi-Fi-andTCP-stacks(thesoftwarethatrunsinthebackgroundandhandlesallWi-FiandIPconnections).Ifyourcodetakestoolongtoexecute,anddon’tlettheTCPstacksdotheirthing,itmightcrash,oryoucouldlosedata.It’sbesttokeeptheexecutiontimeofyouloopunderacoupleofhundredsofmilliseconds.
Everytimethemainloopisrepeated,yoursketchyieldstotheWi-FiandTCPtohandleallWi-FiandTCPrequests.
Ifyourlooptakeslongerthanthis,youwillhavetoexplicitlygiveCPUtimetotheWi-Fi/TCPstacks,byusingincludingdelay(0);oryield();.Ifyoudon’t,networkcommunicationwon’tworkasexpected,andifit’slongerthan3seconds,thesoftWDT(WatchDogTimer)willresettheESP.IfthesoftWDTisdisabled,afteralittleover8seconds,thehardwareWDTwillresetthechip.
![Page 9: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/9.jpg)
Fromamicrocontroller’sperspectivehowever,3secondsisaverylongtime(240millionclockcycles),sounlessyoudosomeextremelyheavynumbercrunching,orsendingextremelylongstringsoverSerial,youwon’tbeaffectedbythis.Justkeepinmindthatyouaddtheyield();insideyourfororwhileloopsthatcouldtakelongerthan,say100ms.
SourcesThisiswhereIgotmostofmyinformationtowritthisarticle,there’ssomemoredetailsontheGitHubpages,ifyou’reintosomemoreadvancedstuff,likeEEPROMordeepsleepetc.
https://github.com/esp8266/Arduino/issues/2942https://github.com/esp8266/Arduino/pull/2533/fileshttps://github.com/esp8266/Arduino/blob/master/doc/libraries.mdhttps://github.com/esp8266/Arduino/blob/master/doc/reference.mdhttps://github.com/esp8266/Arduino/blob/master/doc/boards.md
![Page 10: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/10.jpg)
Wi-FiUsingtheESP8266asasimplemicrocontrollerisgreat,butthereasonwhymostpeopleuseit,isitsWi-Ficapabilities.Inthischapter,we'lldiveintothewonderfulworldofnetworkprotocols,likeWi-Fi,TCP,UDP,HTTP,DNS...Alltheseacronymsmightintimidateyou,butI'lltrymybesttoexplainthemstep-by-stepandinaneasyway.
Someparagraphsareinitalic.Theseprovidesomeextrainformation,butarenotcriticaltounderstandingtheESP'sWi-Fifunctions,sodon'tgetfrustratediftherearethingsyoudon'tunderstand.
It'sreallyhardtogiveaclearexplanation,withoutover-complicatingthingsandwhilekeepingitshortenoughaswell.Ifyou'vegotanyfeedbackorremarks,besuretoleaveacommenttohelpimprovethisarticle.Thanks!
TheTCP/IPstackThesystemmostpeoplerefertoas'TheInternet'isn'tjustoneprotocol:it'sanentirestackoflayersofprotocols,oftenreferredtoastheTCP/IPstack.We'llgooverthesedifferentlayers,becauseweneedtounderstandhowourESP8266communicateswithotherdevicesonthenetwork.
Layer ProtocolsApplication HTTP,FTP,mDNS,WebSocket,OSC...Transport TCP,UDPInternet IPLink Ethernet,Wi-Fi...
TheLinklayer
Thelinklayercontainsthephysicallinkbetweentwodevices,anEthernetcable,forexample,oraWi-Ficonnection.Thisisthelayerthatisclosesttothehardware.ToconnectanESP8266tothenetwork,youhavetocreateaWi-Filink.Thiscanhappenintwodifferentways:
1. TheESP8266connectstoawirelessaccesspoint(WAPorsimplyAP).TheAPcanbebuilt-intoyourmodemorrouter,forexample.Inthisconfiguration,theESPactslikeawirelessstation.
2. TheESP8266actsasanaccesspointandwirelessstationscanconnecttoit.Thesestationscouldbeyourlaptop,asmartphone,orevenanotherESPinstationmode.
OncetheWi-Filinkisestablished,theESP8266ispartofalocalareanetwork(LAN).AlldevicesonaLANcancommunicatewitheachother.Mostofthetime,theAPisconnectedtoaphysicalEthernetnetworkaswell,thismeansthattheESP8266canalsocommunicatewithdevicesthatareconnectedtotheAP(modem/router)viaawiredEthernetconnection(desktopcomputers,gamingconsolesandset-topboxes,forinstance).IftheESP8266isinaccesspointmode,itcancommunicatewithanystationthatisconnectedtoit,andtwostations(e.g.alaptopandasmartphone)canalsocommunicatewitheachother.
TheESPcanbeusedinAP-only,station-only,orAP+stationmode.
TL;DR
Thelinklayeristhephysicallinkbetweendevices:inthecaseoftheESP8266,thisisaWiFiconnection.TheESPcanactasastationandconnecttoanaccesspoint,oractasanaccesspointandletotherdevicesconnecttoit.
TheInternetorNetworklayer
Althoughthedevicesarenowphysicallyconnected(eitherthroughactualwires(Ethernet)orthroughradiowaves(Wi-Fi)),theycan'tactuallytalktoeachotheryet,becausetheyhavenowayofknowingwheretosendthemessageto.That'swheretheInternetProtocol(IP)comesin.EverydeviceonthenetworkhasapersonalIPaddress.TheDHCPserver(DynamicHostConfigurationProtocolServer)makessurethattheseaddressesareunique.Thismeansthatyoucannowsendamessagetoaspecificaddress.
TherearetwoversionsoftheInternetProtocol:IPv4andIPv6.IPv6isanimprovedversionofIPv4andhasmuchmoreaddressesthanIPv4(becausetherearemuchmoredevicesthanavailableIPv4addresses).Inthisarticle,we'llonlytalkaboutIPv4addresses,sincemostLANsstillusethem.
TheIPaddressconsistsof4numbers,forexample192.168.1.5isavalidIPv4address.Itactuallyconsistsoftwoparts:thefirstpartis192.168.1,thisistheaddressofthelocalnetwork.Thelastdigit,5inthiscase,isspecifictothedevice.
ByusingIPaddresses,wecanfindtheESP8266onthenetwork,andsendmessagestoit.TheESPcanalsofindourcomputerorourphone,ifitknowstheirrespectiveIPaddresses.
Sub-netmask(optional)
ThissubdivisionoftheIPaddressisdeterminedbythesub-netmask,oftenwrittenas255.255.255.0.Youcanseethatitconsistsoffournumbers,justliketheIPaddress.Ifapartofthesub-netmaskis255,itmeansthatthecorrespondingpartoftheIPaddressispartofthenetworkaddress,ifit's0,thecorrespondingIPpartispartoftheaddressofthespecificaddress.Adifferentnotationto"IP:192.168.1.5,sub-netmask:255.255.255.0"wouldbe"192.168.1.5/24",becausethebinaryrepresentationofthesub-netmaskis11111111.11111111.11111111.00000000,andithas24ones.Ifyouwanttoknowmoreaboutsub-nets,I'drecommendyoutoreadtheWikipediaarticle.(Aquicktiptohelpyouremember:it'scalledthesub-netmask,becauseifyouperformabitwiseANDoperationontheIPaddressandthesub-netmask(i.e.usethesub-netmaskasamaskfortheIPaddress),yougettheaddressofthesub-net.)
![Page 11: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/11.jpg)
MACaddressesandARP(optional)
ItisactuallyimpossibletosendpacketsdirectlytoanothermachineusingonlytheIPaddress.TosendapackettoaspecificdeviceontheLAN(Wi-FiorEthernet),youhavetoknowitsMAC-address.TheMACaddressisauniquenumberthatisuniqueforeverynetworkdevice,anditneverchanges,it'shardwiredinthenetworkchip.ThismeansthateveryESP8266,everynetworkcard,everysmartphone...evermade,hasadifferentMACaddress.SobeforetheESPcansendapackettoyoursmartphoneforexample,ithastoknowitsMACaddress.Itdoesn'tknowthisyet,theESPonlyknowstheIPaddressofthesmartphone,say192.168.1.6.Todothis,theESPsendsabroadcastmessage(i.e.amessageaddressedtoalldevicesontheLAN)saying"I'mlookingfortheMACaddressofthedevicewiththeIPaddress192.168.1.6".TheESPalsoincludesitsownIPandMACaddresswiththemessage.Whenthesmartphonereceivesthisbroadcastmessage,itrecognizesitsownIPaddress,andrespondstotheESPbysendingitsownMACaddress.NowtheESPandthephonebothknoweachother'sIPandMACaddresses,andtheycancommunicateusingIPaddresses.ThismethodiscalledtheAddresResolutionProtocol,orARP.
WhatabouttheInternet?
Asyoumighthavenoticed,Ionlytalkedaboutthelocalareanetwork,thesearethecomputersinyourownhouse.SohowcantheESP8266communicatewiththeInternet,youmayask?Well,there'salotofnetworkinfrastructureinvolvedin'TheInternet',andtheyallobeytheIPrules,tomakesuremostofyourpacketsarriveattheredestination.It'snotthatsimpleofcourse,there'salotofthingsgoingon,likeroutingandNetworkAddressTranslation(NAT),butthatfallsoutsidethescopeofthisarticle,andit'snotreallysomethingmostpeoplehavetoworryabout.
TL;DR
TheInternetlayerusesIPaddressesinordertoknowwhereitshouldsendthedata.Thismeansthattwodevicescannowsendpacketsofdatatoeachother,evenovertheInternet.
TheTransportlayer
ThedifferentdevicesinthenetworkdotheirbesttodelivertheseIPpacketstotheaddressee,however,it'snotuncommonforapackettogetlost,soitwillneverarrive.Orthepacketmightgetcorruptedontheway:thedataisnolongercorrect.IPalsocan'tguaranteethatthepacketsarriveinthesameordertheyweresentin.Thismeansthatwecan'treliablysendmessagesyetbyonlyusingthelinkandtheInternetlayer,sincewecanneverknowwhenandwhetherapacketwillarrive,orknowforcertainthatareceivedpacketiscorrect.WeneedathirdlayerontopoftheInternetlayer:theTransportlayer.
Therearemainlytwoprotocolsthatmakeupthisthirdlayer:theTransmissionControlProtocol(TCP)andtheUserDatagramProtocol(UDP).
TCPmakessurethatallpacketsarereceived,thatthepacketsareinorder,andthatcorruptedpacketsarere-sent.Thismeansthatitcanbeusedforcommunicationbetweenmultipleapplications,withouthavingtoworryaboutdataintegrityorpacketloss.Thisiswhyit'susedforthingslikedownloadingwebpages,sendingemail,uploadingfilesetc.UDPontheotherhand,doesn'tguaranteethateverypacketreachesitsdestination,itdoescheckforerrorshowever,butwhenitfindsone,itjustdestroysthepacket,withoutre-sendingit.Thismeansthatit'snotasreliableasTCP,butit'sfaster,andhasamuchlowerlatency,becauseitdoesn'trequireanopenconnectiontosendmessages,likeTCPdoes.That'swhyit'susedinvoiceandvideochats,andforexampleinonlinegames.
IfyouwanttoknowmoreaboutthedifferencesbetweenTCPandUDP,checkoutthisvideo.
TL;DR
TheIPprotocolisnotreliable,andhasnoerrorchecking.TCPsolvesthisbyre-sendinglostorcorruptpackages,andorderspacketsthatarereceivedinthewrongorder.UDPalsochecksforcorruptpackages,butdoesn'tre-sendthem,soithaslesslatencythanTCP.
TheApplicationlayer
WenowhavereliablecommunicationusingTCP,butthere'sstilloneproblem.Thinkofitthisway:youaresendingaletter,andTCPguaranteesthatitwillarriveatitsdestination,butifthereceiverdoesn'tunderstandthelanguageit'swrittenin,hewon'tknowwhattodowithit.Inotherwords,weneedafourthlayerofprotocols,fortwoprogramstobeabletocommunicatewitheachother.There'slotsofdifferentprotocolsoutthere,butwe'llmostlyfocusontheprotocolsforwebserversandbrowsers.
HyperTextTransferProtocol
TheHyperTextTransferProtocol,orHTTP,istheprotocol(cfr.language)thatisusedbybothwebserversandwebclientsinordertocommunicate.Itusestexttoperformsendrequestsandresponsesfromtheclienttotheserverandbackagain.Forexample,whenyoutypehttp://www.google.comintotheaddressbarofawebbrowser(client),itwillsendanHTTPGETrequesttotheGooglewebserver.TheserverunderstandsthisHTTPrequest,andwillsendtheGooglewebpageasaresponse.OrwhenyouuploadanimagetoInstagram,yourbrowsersendsanHTTPPOSTrequestwithyourselfieattachedtotheInstagramserver.Theserverunderstandstherequest,savestheimageandaddsitintothedatabase,sendstheURLofthenewimagebacktoyourbrowser,andthebrowserwilladdtheimageonthewebpage.Asyoucansee,neithertheclientnortheserverhastoworryabouttheintegrityofthemessagestheysend,andtheyknowthattherecipientunderstandstheirlanguage,andthatitwillknowwhattodowithacertainHTTPrequest.MostmodernsitesuseasecureversionofHTTP,calledHTTPS.Thissecureconnectionencryptsthedata,forsecurityreasons.(Youdon'twantanyonereadingthepacketsfromyourmailserver,orthepacketsyousenttoyourbank,forinstance.)
WebSocket
HTTPisgreatforthingslikedownloadingwebpages,uploadingphotosetc.butit'squiteslow:everytimeyousendanHTTPrequest,youhavetostartanewTCPconnectiontotheserver,thensendyourrequest,waitfortheservertorespond,anddownloadtheresponse.Wouldn'titbegreatifwedidn'thavetoopenanewconnectioneverytimewewanttosendsomedata,andifwecouldsendandreceivedataatthesametimeatanymomentwe'dlike?That'swhereWebSocketcomestotherescue:youcankeeptheTCPconnectionwiththeserveropenatalltimes,yougetperfectTCPreliability,andit'sprettyfast.
OpenSoundControl
![Page 12: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/12.jpg)
HTTPandWebSocketbothuseTCPconnections.Whatifyouwantlowerlatency?Well,OpenSoundControl,orOSC,usesUDPtosendsmallpiecesofdata,likeints,floats,shorttextetc...withverylowlatency.Itwasoriginallydesignedforcontrollinglowlatencyaudioapplications,butit'saveryflexibleprotocol,soit'softenusedforlow-latencytasksotherthanaudiocontrol.
DomainNameSystem
Asmentionedbefore,youcanonlysendamessagetoanothercomputerifyouknowitsIPaddress.ButwhenyoubrowsetheInternet,youonlyknowawebsite'sdomainname(e.g.www.google.com).YourcomputerusestheDomainNameSystemtotranslatethisdomainnametotherightIPaddress.Moreonthislater.
Sources
https://en.wikipedia.org/wiki/Internet_protocol_suitehttps://en.wikipedia.org/wiki/Port_(computer_networking)https://en.wikipedia.org/wiki/Transmission_Control_Protocolhttps://en.wikipedia.org/wiki/Internet_Protocolhttps://en.wikipedia.org/wiki/User_Datagram_Protocol
![Page 13: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/13.jpg)
UploadingsketchestotheESP8266TheuploadprocedureforESP8266boardsisalittledifferentfromthenormalArduinoprocedure.MostArduinoswillautomaticallyresetwhenanewprogramisbeinguploaded,andwillautomaticallyenterprogrammingmode.OnsomeESPboardsyouhavetomanuallyenterprogrammingmode,andonthebare-bonesmodules,youevenhavetoresetthemmanually.However,therearesomesimplecircuitsyoucanusetogetautomaticuploads.
Auto-resetThisonlyappliestoboardswithoutanon-boardUSB-to-Serialconverter.
IftheUSB-to-Serialconverteryou'reusinghasaDTRflowcontrolline,youcanautomatetheresetsignal.WhensendingdatatotheESP,theDTRlinegoeslow,andstayslowforsometime.ToresettheESP,weneedalowpulseontheRSTpin.TheproblemisthattheDTRpinstayslow.Tosolvethis,we'regoingtobuildacrudeedgedetectorcircuit,usingacapacitor.Takealookatthefollowingschematic:
Youmightrecognizethatthisisbasicallyalow-cutfilter.Innormalconditions,DTRishigh(3.3V),andtheresetlineisalsohigh,becauseofthepull-upresistorR2.Thismeansthatthevoltageacrossthecapacitoris0V.WhenDTRsuddenlydrops(to0V),thevoltageacrossthecapacitorisstill0V,meaningthattheresetlinewillbeat0V+0V=0V,andaresetistriggered.
However,C1immediatelystartschargingthroughR2,andreaches3.3V.Atthispoint,DTRisstillat0V,meaningthatthere'snow3.3Vacrossthecapacitor.WhenDTRrisesagain,theresetlinewillbeat3.3V+3.3V=6.6V,andthenimmediatelystartstodischargethroughR2,finallyreaching3.3Vagain,with0VacrossC1.Thisisaproblem:6.6VcandamagetheESP,sowehavetofindawaytogetridofthepositivepeak.
OneglanceatthisMATLABsimulationshowsustheproblemevenbetter:
![Page 14: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/14.jpg)
ThebluesignalisthevoltageontheDTRpin,andtheyellowsignalisthevoltageontheresetpin.
Thesolutionistoaddadiode:whilechargingthecapacitor,itshouldn'tchangeanything,soitshouldbereversebiased(justafancywayofsayingthatit'snotconductinganycurrentbecausethepolarityistheotherwayaround),andwhilethecapacitorisdischarging,itshoulddischargethecapacitor"immediately".Here'swhatthatlookslike:
Let'srunthesimulationagaintocheckifourproblemissolved:
![Page 15: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/15.jpg)
Asyoucansee,the6.6Vpeakisnowverynarrow,justlikewewanted.It'simpossibletodischargethecapacitorinstantly,thatwouldrequireacapacitorandadiodewith0Ωofseriesresistance,andaninfinitecurrent,whichisimpossible,obviously.There'salsoasmallerbutrelativelywidepeakofapproximately3.9V.Thisisbecauseadiodeonlyconductswhenthevoltageacrossitishigherthan~600mV.Thismeansthatthelast0.6Vthat'sleftinthecapacitor(from3.9to3.3V)willstillbedischargedthroughR2only.Nevertheless,thevoltagepeakismuchlowerandnarrowerthanwithoutthediode,andit'ssafetoconnecttotheESP8266.
ThisexactcircuitisalsousedintheArduinoUno,forexample.
Note:ifyoufollowedtheinstructionsinthehardwarestepcorrectly,youshouldalreadyhaveaddedR2toyourESP.
HowtouseAuto-reset
Tousethisauto-resetcircuit,connectittotheDTRlineofyourUSB-to-Serialconverter,andtotheresetlineoftheESP,asshowninthediagram.Thenclickcompile(justbecausethefirstcompilationcantakequitesometime).GotoTools>Resetandselect'ck'.Whenit'sdonecompiling,holddowntheprogrambuttonweaddedinthehardwarestep,andclickupload.Waitforittosay"Uploading..."andthenreleasetheprogrambutton.
Auto-resetandAuto-program
Thisonlyappliestoboardswithoutanon-boardUSB-to-Serialconverter.
Themethodabovestillrequiresyoutopressabuttontouploadanewsketch.IfyourUSB-to-SerialconverterhasaRTSlineaswellasaDTRline,youcanautomatetheentireprocess.
![Page 16: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/16.jpg)
Youmayfindoutthatthe4.7kΩresistordoesn'tworkforyou.Inthatcase,trysomeothervalue,like10kΩ,forexample.
ThismethodwasfirstusedintheNodeMCU,sogotoTools>ResetMethod,andselect"nodemcu".ThiswilldrivetheDTR&RTSpinshighandlowintherightsequencetogetitinprogrammingmodebeforeuploading.
Thisisbyfarthebestmethod,buttheproblemisthatyouneedaccesstoboththeRTSandDTRpins,whilemostUSB-to-Serialadaptersbreakoutonlyoneofthetwo.
ManualresetandmanualprogramThisonlyappliestoboardswithoutanon-boardUSB-to-Serialconverter.
Ifyoudon'thaveaUSB-to-SerialconverterwithDTRandRTSlines,youcouldalsojustusetheresetandprogrambuttonsweaddedinthehardwarechapter.TogettheESPinprogrammode,GPIO0mustbelowwhilebooting:
1. pressandholdtheresetbutton2. pressandholdtheprogrambutton3. releasetheresetbutton,theESPwillbootinprogrammode4. releasetheprogrambutton5. uploadthesketch
Ifyouwanttogetoutofprogrammodewithoutuploading,justpressreset(withoutpressingtheprogrambutton).
Boardoptions
IfyourspecificboardisintheTools>Boardlist(e.g.NodeMCU,SparkFunandAdafruitboards),youcanjustselectit,andyouwillgettherightsettings.Whenyourboardisn'tinthelist,you'llhavetoselectaGenericESP8266.Inthatcasethere'slotsofnewoptionsintheToolsmenuoftheArduinoIDE,solet'sgooverthemandpicktherightsettings.
FlashMode
LikeIsaidbefore,theESP8266usesanexternalflashchipforstorage.Youcancommunicatewiththischipover2datalines(DIO),oroverall4datalines(QIO).Using4linesistwotimesfasterthan2lines,soinmostcases,youshouldchooseQIO.(Ifyou'redoingsomeadvancedstuffandyouneed2moreGPIOpins,youcoulduse2linesinsteadof4,andusethe2linesasI/O.Mostmodulesdon'tgiveyouaccesstothesepins,though.)
FlashSize
Differentboards/moduleshavedifferentsizesofflashchipsonboard.Thereareboardswith512kB,1MB,2MBand4MBofflash.To
![Page 17: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/17.jpg)
knowhowmuchflashyourboardhas,youcantrytheExamples>ESP8266>CheckFlashConfigtoseeifyourflashsettingiscorrect,oryoucancheckthespecificationsofyourspecificboardonline.YoucanalsoselecttheSPIFFS(SPIFlashFileSystem)size.TheSPIFFSpartitionisasmallfilesystemtostorefiles.Ifyou'renotusingit,youcanselecttheminimum.Lateroninthearticle,we'lluseSPIFFS,andI'llremindyoutoselectalargerSPIFFSsize,butfornow,itdoesn'treallymatter.
Debugport
There'saloadofthingsgoingonwhentheESPisrunning:ThingslikeWi-Ficonnections,TCPconnections,DNSlookups...younameit.Allthesesmalltasksproduceawholelotofdebugoutputtohelpyoutroubleshoot.However,inanormalsituation,whereyourprogramisbehavingasexpected,youdon'tneedallthosedebugmessagestofloodtheSerialMonitor,soyoucanjustturnthemoffbyselecting'Disabled'.Ifyoudowishtoreceivedebugmessages,youcanselecttheporttosendthemto.(Serialonpins1and3,orSerial1onpin2)
Debuglevel
Thisallowsyoutochoosewhatkindofdebugmessagesyouwanttoshow.
ResetMethod
Asmentionedintheparagraphsabove,therearedifferentmethodsforauto-resetandauto-program.Ifyou'reusingthefirstmethod(usingtheedgedetector),youshoulduse'ck',ifyouusethetwo-transistorcircuit,select'nodemcu'.
FlashFrequency
Ifyouneedsomeextramemoryspeed,youcouldchangetheflashfrequencyfrom40MHzto80MHz.ThisistheclockfrequencyoftheSPI/SDIOlink.
CPUFrequency
IfyouneedsomeextraCPUperformance,youcandoubletheclockspeedfrom80MHzto160MHz.It'sactuallyanoverclock,butI'veneverhadanyissuesorinstability.
UploadSpeed
ThebaudrateforuploadingtotheESP.Thedefaultis115200baud,butyoucangohigher(ifyou'rechangingyoursketchalot,itmightbetooslow).921600baudworksmostofthetime,butyoumaygetanerrorsometimes,ifthat'sthecase,switchingbackto115200willprobablysolveallproblems.
![Page 18: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/18.jpg)
EstablishingaWi-FiconnectionLikeImentionedinthepreviouschapter,theESP8266canoperateinthreedifferentmodes:Wi-Fistation,Wi-Fiaccesspoint,andbothatthesametime.We'llstartbylookingattheconfigurationofaWi-Fistation.
Stationmode
Connectingtoonespecificnetwork
#include<ESP8266WiFi.h>//IncludetheWi-Filibrary
constchar*ssid="SSID";//TheSSID(name)oftheWi-Finetworkyouwanttoconnecttoconstchar*password="PASSWORD";//ThepasswordoftheWi-Finetwork
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');WiFi.begin(ssid,password);//ConnecttothenetworkSerial.print("Connectingto");Serial.print(ssid);Serial.println("...");
inti=0;while(WiFi.status()!=WL_CONNECTED){//WaitfortheWi-Fitoconnectdelay(1000);Serial.print(++i);Serial.print('');}
Serial.println('\n');Serial.println("Connectionestablished!");Serial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer}
voidloop(){}
Thecodetoconnecttoawirelessaccesspointisrelativelystraightforward:entertheSSIDandthepasswordofthenetworkyouwanttoconnectto,andcalltheWiFi.beginfunction.Thenwaitfortheconnectiontocomplete,etvoilà,yourESP8266isnowconnectedtoyourLocalAreaNetwork.
Don'tbelieveme?I'llproveittoyou:opentheSerialmonitor(CTRL+SHIFT+M)anduploadthesketch.Youshouldseesomethinglikethis:
ConnectingtoSSID...123456...
Connectionestablished!IPaddress: 192.168.1.3
Nowgotoyourcomputerandopenupaterminal:OnWindows,searchfor"CommandPrompt",onMacorLinux,searchfor"Terminal".Youcouldalsousetheshortcuts:onWindows,hit +R,type"cmd"andhitenter,onLinux,useCTRL+ALT+T.
Next,typeping,andthentheIPaddressyoureceivedintheSerialmonitor.Ifyou'reonMacorLinux,useCTRL+Ctostopitafteracoupleoflines.Theoutputshouldlooksomethinglikethis:
user@computername:~$ ping192.168.1.3PING192.168.1.3(192.168.1.3)56(84)bytesofdata.64bytesfrom192.168.1.3:icmp_seq=1ttl=128time=6.38ms64bytesfrom192.168.1.3:icmp_seq=2ttl=128time=45.2ms64bytesfrom192.168.1.3:icmp_seq=3ttl=128time=69.1ms64bytesfrom192.168.1.3:icmp_seq=4ttl=128time=94.0ms64bytesfrom192.168.1.3:icmp_seq=5ttl=128time=20.5ms64bytesfrom192.168.1.3:icmp_seq=6ttl=128time=7.37ms^C---192.168.1.3pingstatistics---6packetstransmitted,6received,0%packetloss,time5003msrttmin/avg/max/mdev=6.384/40.463/94.047/32.588ms
ThepingcommandsendssmallpacketstotheIPaddressoftheESP8266.WhentheESPreceivessuchapacket,itsendsitbacktothesender.PingispartofthesecondlayeroftheTCP/IPstack,theInternetlayer.ItreliesonboththeDataLinklayer(Wi-Fi)andtheInternetProtocol*.Youcanseethatintheexampleabove,wesent6packetstotheESP,andwealsoreceived6response(echo)packets.ThistellsusthattheDataLink,theWi-Ficonnection,andtheInternetProtocolareworkingcorrectly.
WenowknowthattheESPcansuccessfullycommunicatewithotherdevicesonthenetwork,andifyourlocalnetworkisonline(ifitisconnectedtotheInternetviayourmodem),theESPcanalsocommunicatewithanydeviceontheweb!
PingisagreattooltocheckiftheESP(oranydevice,really)isstillconnectedtothenetwork,andifit'sstillworkingfine.OnedrawbackisthatIPaddressescanchangeovertime,butthat'saproblemwe'lladdressinoneofthefollowingchapters...
(*)I'msimplifyingthingsabithere.Actually,pingispartoftheInternetControlMessageProtocol(ICMP),that'salsopartofthesecondlayer,justliketheInternetProtocol.Don'tworrytoomuchaboutit,justrememberthatifyoucansendpingpacketstoadevice,youcanalsosendIPpackets.
![Page 19: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/19.jpg)
Thedevicewiththeantennaservesmanydifferentpurposes:
Accesspoint:OtherWi-Fidevicescanconnecttoit,tobepartofthelocalnetwork.Router:ItroutesIPpacketstotherightsub-netssothattheywillarriveattheirdestination.E.g.ifthecomputersendsamessagethatismeantfortheESPovertheEthernetsub-net,therouterwillsendthepackettotheWi-Fisub-net,becauseitknowsthat'swheretheESPis.Modem:iftheroutercan'tfindtheaddresseeonthelocalnetwork,thepacketwillbepassedontotheintegratedmodem,anditwillbesenttotheInternetServiceProvideroveraDSLline,headingfortheInternet,wherelotsofotherrouterswilltrytogetthepackettotherightdestination.
Butinreality,youdon'thavetoworrytoomuchaboutit,becauseit'salldoneforyou,inafractionofasecondwithoutyouevennoticingit!
Automaticallyconnecttothestrongestnetwork
Thesketchabovemightbeenoughforyourspecificapplication,butifyouneedtobeabletoconnecttomultipleWi-Finetworks,forexampletheWi-FiathomeandtheWi-Fiattheoffice,itwon'twork.Tosolvethisproblem,we'llusetheWi-Fi-Multilibrary:Youcanaddasmanynetworksasyoulike,anditautomaticallyconnectstotheonewiththestrongestsignal.
#include<ESP8266WiFi.h>//IncludetheWi-Filibrary#include<ESP8266WiFiMulti.h>//IncludetheWi-Fi-Multilibrary
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnect:scanforWi-Finetworks,andconnecttothestrongestofthenetworksabovedelay(1000);Serial.print('.');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer}
voidloop(){}
AccessPointmode
![Page 20: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/20.jpg)
ToconfiguretheESP8266asanaccesspoint,toallowotherdeviceslikesmartphonesorlaptopstoconnecttoit,youcanusethesoftAPfunction:
#include<ESP8266WiFi.h>//IncludetheWi-Filibrary
constchar*ssid="ESP8266AccessPoint";//ThenameoftheWi-Finetworkthatwillbecreatedconstchar*password="thereisnospoon";//Thepasswordrequiredtoconnecttoit,leaveblankforanopennetwork
voidsetup(){Serial.begin(115200);delay(10);Serial.println('\n');
WiFi.softAP(ssid,password);//StarttheaccesspointSerial.print("AccessPoint\"");Serial.print(ssid);Serial.println("\"started");
Serial.print("IPaddress:\t");Serial.println(WiFi.softAPIP());//SendtheIPaddressoftheESP8266tothecomputer}
voidloop(){}
Toseeifitworks,opentheWi-Fisettingsonyourcomputer,lookforanetworkcalled"ESP8266AccessPoint",enterthepassword"thereisnospoon",andconnecttoit.Thenopenaterminal,andpingto192.168.4.1(thisisthedefaultIPaddressofourESPAP).You'llseethattheESPrespondstoyourpings.
However,ifyoutrytogotoanonlinewebsite,you'llgetatimeoutoraDNSerror.ThisisbecausetheESPitselfisnotconnectedtotheinternet.Thesub-netthatconsistsoftheESPandthecomputerisnotconnectedtoanyothernetworks,sothere'snowayforapacketonthisnetworktomakeittotheInternet.
IfyouconnectedasecondstationtotheESPaccesspointontheotherhand,youwouldbeabletopingfromonestationtotheotherwithoutproblems,becausethey'reonthesamenetwork.
![Page 21: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/21.jpg)
MulticastDomainNameSystemDNS
Let'sfaceit,constantlytypingIPaddressesisreallycumbersome,anditwouldbeimpossibletorememberallyourfavoritewebsites'addresses,especiallyiftheyuseIPv6.That'swhydomainnameswereintroduced:asimplestringoftextthat'seasytoremember,forexamplewww.google.com.
However,tosendarequesttoawebsite,yourcomputerstillneedstoknowitsIPaddress.That'swhereDNScomesin.ItstandsforDomainNameSystem,andisawaytotranslateawebsite'sdomainnametoitsIPaddress.OntheInternet,therearealotofDNSservers.EachDNSserverhasalonglistofdomainnamesandtheircorrespondingIPaddresses.DevicescanconnecttoaDNSserverandsendadomainname,theDNSserverwillthenrespondwiththeIPaddressoftherequestedsite.Youcouldcompareittoatelephonedirectory:youcanlookupanametofindthecorrespondingphonenumber.
TheDNSlookuphappenscompletelyinthebackground:whenyougotoawebsiteinyourbrowser,itwillfirstsendarequesttoaDNSserver(thisimpliesthatthecomputerknowstheIPaddressoftheDNSserveritself),waitfortheresponseofthelookup,andthensendtheactualrequesttotherightIPaddress.
mDNS
DNSworksgreatfornormalsitesontheInternet,butmostlocalnetworksdon'thavetheirownDNSserver.Thismeansthatyoucan'treachlocaldevicesusingadomainname,andyou'restuckusingIPaddresses...
Fortunately,there'sanotherway:multicastDNS,ormDNS.mDNSusesdomainnameswiththe.localsuffix,forexamplehttp://esp8266.local.Ifyourcomputerneedstosendarequesttoadomainnamethatendsin.local,itwillsendamulticastquerytoallotherdevicesontheLANthatsupportmDNS,askingthedevicewiththatspecificdomainnametoidentifyitself.ThedevicewiththerightnamewillthenrespondwithanothermulticastandsenditsIPaddress.NowthatyourcomputerknowstheIPaddressofthedevice,itcansendnormalrequests.
Luckilyforus,theESP8266ArduinoCoresupportsmDNS:
#include<ESP8266WiFi.h>//IncludetheWi-Filibrary#include<ESP8266WiFiMulti.h>//IncludetheWi-Fi-Multilibrary#include<ESP8266mDNS.h>//IncludethemDNSlibrary
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnect:scanforWi-Finetworks,andconnecttothestrongestofthenetworksabovedelay(1000);Serial.print(++i);Serial.print('');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer
if(!MDNS.begin("esp8266")){//StartthemDNSresponderforesp8266.localSerial.println("ErrorsettingupMDNSresponder!");}Serial.println("mDNSresponderstarted");}
voidloop(){}
Uploaditandopenpingagain.Trytopingtoesp8266.local:
user@computername:~$ pingesp8266.localPINGesp8266.local(10.92.237.128)56(84)bytesofdata.64bytesfrom10.92.237.128:icmp_seq=1ttl=128time=5.68ms64bytesfrom10.92.237.128:icmp_seq=2ttl=128time=3.41ms64bytesfrom10.92.237.128:icmp_seq=3ttl=128time=2.55ms64bytesfrom10.92.237.128:icmp_seq=4ttl=128time=2.19ms64bytesfrom10.92.237.128:icmp_seq=5ttl=128time=2.29ms64bytesfrom10.92.237.128:icmp_seq=6ttl=128time=2.74ms^C---esp8266.localpingstatistics---6packetstransmitted,6received,0%packetloss,time5007msrttmin/avg/max/mdev=2.190/3.148/5.687/1.202ms
Asyoucansee,pingwillautomaticallyfindtheIPaddressoftheESPforyou.
mDNSissupportedonWindows,OSX,LinuxandiOS,butnot(yet?)onAndroid.It'sarealshamethatAndroiddoesn'tsupportit,youcanhelpbystarringthisissuereportfortheChromiumprojecttoaskformDNSsupportinChromeonAndroid.
Ofcourse,youcanchangethedomainnameoftheESPbychangingtheparameterofMDNS.begin.
![Page 22: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/22.jpg)
![Page 23: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/23.jpg)
ESP8266WebServerBeingabletopingtheESPisquiteanachievementifyoulookatitfromatechnicalpointofview,butformostpeople,it'snotthatexciting,andnotreallyuseful.Inthischapter,I'llcoverthebasicsofawebserver,andteachyouhowtohostawebpageontheESP.
WebserversAwebserverisanInternet-connecteddevicethatstoresandservesfiles.Clientscanrequestsuchafileoranotherpieceofdata,andtheserverwillthensendtherightdata/filesbacktotheclient.RequestsaremadeusingHTTP.
HTTP
HTTPortheHypertextTransferProtocolisthetext-basedprotocolusedtocommunicatewith(web)servers.TherearemultipleHTTPrequestmethods,butI'llonlycoverthetwomostwidelyusedones:GETandPOST.
HTTPGET
GETrequestsareusedtoretrievedatafromaserver,awebpageforinstance.Itshouldn'tchangeanythingontheserver,itjustgetsthedatafromtheserver,withoutsideeffects.
Whenyouopenawebpageinyourbrowser,itwilltaketheURLandputitinanHTTPGETrequest.Thisisjustplaintext.ThenitwillsendtherequesttotherightserverusingTCP.Theserverwillreadtherequest,checktheURL,andsendtherightHTTPresponseforthatURLbacktothebrowser.
TheanatomyofaGETrequest
ThemostimportantpartsofaGETrequestaretherequestlineandthehostheader.Let'stakealookatanexample:Ifyouclickthefollowinglink:https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html,yourbrowserwillsendoutthefollowingHTTPrequest:
GET/Protocols/rfc2616/rfc2616-sec5.htmlHTTP/1.1Host:www.w3.orgConnection:keep-alivePragma:no-cacheCache-Control:no-cacheUpgrade-Insecure-Requests:1User-Agent:Mozilla/5.0(X11;Linuxx86_64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/56.0.2924.87Safari/537.36Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8DNT:1Referer:https://www.google.be/Accept-Encoding:gzip,deflate,sdch,brAccept-Language:en-US,en;q=0.8
Thefirstlineistherequestline:itcontainstherequestmethod:GET,inthiscase,theURIorUniformResourceIdentifier:/Protocols/rfc2616/rfc2616-sec5.html,andtheHTTPversion:1.1.Thesecondlineisthehostheader,itspecifiesthedomainnameofthehost(server).Therearemanyotherheadersaswell,butthey'renotreallyimportantwhenusinganESP8266.MostserverswillcheckiftheURIisafileontheirfilesystem,andifthat'sthecase,they'llsendthatfileasaresponse.
ViewingHTTPheadersinthebrowser
Ifyouwanttochecktheheadersyourbrowsersends,youcanpressF12,gotothenetworktab,reloadthepage,andclicktherequestyouwanttoinspect.Ifyouwant,youcanclick'viewsource',thiswillshowyoutheactualHTTPtext.Here'swhatthatlookslikeinChrome:
![Page 24: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/24.jpg)
Sendingextrainformationtotheserver
Sometimes,youmightwanttoaddextrainformationtotheGETrequest.Youcansendkey-valuepairsbyaddingaquestionmark(?)totheURI,followedbykey=value.Multiplepairsareseparatedbyanampersand(&).Forexample:
GET/get-phone-number.php?firstName=John&lastName=DoeHTTP/1.1Host:www.phonebook.example.com...
Ifyouuseanyspecialcharactersinthekeyorvaluenames,youhavetoURL-encodethem.
HTTPPOST
POSTrequestsareusedtosenddatatotheserver,forexample,tosendyourusernameandpasswordtotheserverwhenyoulogin,orwhenyouuploadaphoto.UnlikeGET,POSTcanchangethedataontheserverorthestateoftheserver.POSThasabodythatcancontaindatathatissenttotheserver.
TheanatomyofaPOSTrequest
Forexample,theloginpageofyourfavoritesitemightsendsomethinglikethiswhenyouenteryourcredentialsandclicktheloginbutton:
POST/login.phpHTTP/1.1Host:www.example.comConnection:keep-aliveContent-Length:480Origin:http://www.example.comContent-Type:multipart/form-data;boundary=----WebKitFormBoundaryQNEJOasMvgAOg8Kt...
Asyoucansee,therequestlinenowhasthePOSTmethodinit,andisstillfollowedbyaURI,/login.php,andtheHTTPversion,1.1.Thehostheaderstillcontainsjustthedomainname.
Therealdifferenceistherequestbody:aGETrequesthasnopayload,whileyoucanaddalotofdatatothebodyofaPOSTrequest.Thisdatacouldbenormalkey-valuepairs,likeausernameandapassword,oractualfilesthatarebeinguploaded.AlsonotetheContent-Typeheader:ittellstheserverwhatkindofdatacanbefoundinthebodyofthePOSTrequest.
Let'stakealookatthebodyoftheloginexample:
------WebKitFormBoundaryQNEJOasMvgAOg8KtContent-Disposition:form-data;name="username"
JohnDoe------WebKitFormBoundaryQNEJOasMvgAOg8KtContent-Disposition:form-data;name="password"
p@ssw0rd123------WebKitFormBoundaryQNEJOasMvgAOg8KtContent-Disposition:form-data;name="token"
9i9ZoLHl5pkRAeuKCEu76TbaCnMphwYkPEovEUY9PHk=------WebKitFormBoundaryQNEJOasMvgAOg8Kt--
Asyoucansee,therearethreeparametersinsidethebody,everyparameterhasaname(e.g.username),andavalue(e.g.JohnDoe).
YoucouldalsousethesamesyntaxweusedbeforewhenaddingparameterstoaGETrequest:
![Page 25: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/25.jpg)
POST/add-user.phpHTTP/1.1Host:www.example.comContent-Length:27Content-Type:application/x-www-form-urlencoded...
Andthepayload:
firstName=John&lastName=Doe
Asyoucansee,theContent-Typeheaderisdifferent,indicatingthattheencodingofthevaluesinthepayloadisdifferent.
HTTPstatuscodesAservershouldanswerallrequestswithanHTTPstatuscode.Thisisa3-digitnumberindicatingiftherequestwassuccessfulortellingtheclientwhatwentwrong.Here'satablewithsomeofthemostimportantandusefulones.StatusCode Meaning200 OK:therequestwassuccessful303 SeeOther:usedtoredirecttoadifferentURI,afteraPOSTrequest,forinstance400 BadRequest:theservercouldn'tunderstandtherequest,becausethesyntaxwasincorrect401 Unauthorized:userauthenticationisrequired403 Forbidden:theserverrefusestoexecutetherequest,authorizationwon'thelp404 NotFound:therequestedURIwasnotfound500 InternalServerError:Theserverencounteredanunexpectedconditionandcouldn'tfulfilltherequest
TCP&UDPPorts
Inmostcases,onedevicehasmanydifferentservices,forexample,awebserver,anemailserver,anFTPserver,aSpotifystreamingservice,...IfthedevicehadjustanIPaddress,itwouldbeimpossibletoknowwhichapplicationapacketwassentto.That'swhyeveryservicehasaportnumber.It'sanidentifierforalldifferentservicesorapplicationsonasingledevice.Intheexampleabove,thewebserverwillonlylistenforrequestsonport80,theemailserveronlyonport25,theFTPserveronlyonport20,Spotifywillonlyreceivestreamsonport4371...Tospecifyacertainport,youcanuseacolonaftertheIPaddressofafterthedomainname.Butmostofthetime,youdon'thavetoadditexplicitly.Forexample,allwebserverslistenonport80,soawebbrowserwillalwaysconnecttoport80.
http://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urnhttps://www.w3.org/Protocols/rfc2616/rfc2616-sec10.htmlhttps://en.wikipedia.org/wiki/List_of_HTTP_status_codes
![Page 26: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/26.jpg)
ESP8266FirstWebServerTheactualimplementationofawebserverismucheasierthanitsounds,becausetheESP8266ArduinoCoreincludessomegreatlibrariesthathandleprettymucheverythingforyou.Let'slookatabasicHelloWorld!example.
#include<ESP8266WiFi.h>#include<WiFiClient.h>#include<ESP8266WiFiMulti.h>#include<ESP8266mDNS.h>#include<ESP8266WebServer.h>//IncludetheWebServerlibrary
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
ESP8266WebServerserver(80);//CreateawebserverobjectthatlistensforHTTPrequestonport80
voidhandleRoot();//functionprototypesforHTTPhandlersvoidhandleNotFound();
voidsetup(void){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnect:scanforWi-Finetworks,andconnecttothestrongestofthenetworksabovedelay(250);Serial.print('.');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer
if(MDNS.begin("esp8266")){//StartthemDNSresponderforesp8266.localSerial.println("mDNSresponderstarted");}else{Serial.println("ErrorsettingupMDNSresponder!");}
server.on("/",handleRoot);//Callthe'handleRoot'functionwhenaclientrequestsURI"/"server.onNotFound(handleNotFound);//WhenaclientrequestsanunknownURI(i.e.somethingotherthan"/"),callfunction"handleNotFound"
server.begin();//ActuallystarttheserverSerial.println("HTTPserverstarted");}
voidloop(void){server.handleClient();//ListenforHTTPrequestsfromclients}
voidhandleRoot(){server.send(200,"text/plain","Helloworld!");//SendHTTPstatus200(Ok)andsendsometexttothebrowser/client}
voidhandleNotFound(){server.send(404,"text/plain","404:Notfound");//SendHTTPstatus404(NotFound)whenthere'snohandlerfortheURIintherequest}
There'salotofcodethat'sthesameasintheWi-FiandmDNSexamples.Theactualservercodeisprettystraightforward.First,wecreateaserverinstancethatlistensforHTTPrequestsonport80.Thisisthedefaultportforwebservers.Inthesetup,wetelltheserverwhattodowithcertainHTTPrequests.IftheURI'/'isrequested,theservershouldreplywithaHTTPstatuscodeof200(Ok)andthensendaresponsewiththewords'Helloworld!'.Weputthecodeforgeneratingaresponseinaseparatefunction,andthewetelltheservertoexecuteitwhen'/'isrequested,usingtheserver.onfunction.
Wehaven'tspecifiedwhattheservershoulddoiftheclientrequestsanyURIotherthan'/'.ItshouldrespondwithanHTTPstatus404(NotFound)andamessagefortheuser.Weputthisinafunctionaswell,anduseserver.onNotFoundtotellitthatitshouldexecuteitwhenitreceivesarequestforaURIthatwasn'tspecifiedwithserver.on.
ThenwestartlisteningforHTTPrequestsbyusingserver.begin.Duringtheloop,weconstantlycheckifanewHTTPrequestisreceivedbyrunningserver.handleClient.IfhandleClientdetectsnewrequests,itwillautomaticallyexecutetherightfunctionsthatwespecifiedinthesetup.
Totestitout,uploadthesketch,openanewbrowsertab,andbrowsetohttp://esp8266.local.YoushouldgetawebpagesayingHelloworld!.Ifyoutrytogotoadifferentpage,http://esp8266.local/test,forinstance,youshouldgeta404error:404:Notfound.
TurningonandoffanLEDoverWi-FiWecanusethewebservertoserveinteractivepages,andtoreacttocertainPOSTrequest.Inthefollowingexample,theESP8266hostsawebpagewithabutton.Whenthebuttonispressed,thebrowsersendsaPOSTrequestto/LED.WhentheESPreceivessuchaPOSTrequestonthe/LEDURI,itwillturnonorofftheLED,andthenredirectthebrowserbacktothehomepagewiththebutton.
Inordertoperformthisredirect,theESPhastoaddaLocationheadertotheresponse,andusea303(SeeOther)HTTPstatuscode.
ThebuttontosendthePOSTrequestinthebrowserispartofanHTMLform.YouhavetospecifythetargetURItosendtherequestto,andtherequestmethod,inthiscasethisis"/LED"andPOSTrespectively.
NotethatIchangedthecontenttypeoftheresponsefrom"text/plain"to"text/html".Ifyousenditasplaintext,thebrowserwill
![Page 27: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/27.jpg)
displayitastextinsteadofinterpretingitasHTMLandshowingitasabutton.
#include<ESP8266WiFi.h>#include<WiFiClient.h>#include<ESP8266WiFiMulti.h>#include<ESP8266mDNS.h>#include<ESP8266WebServer.h>
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
ESP8266WebServerserver(80);//CreateawebserverobjectthatlistensforHTTPrequestonport80
constintled=2;
voidhandleRoot();//functionprototypesforHTTPhandlersvoidhandleLED();voidhandleNotFound();
voidsetup(void){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
pinMode(led,OUTPUT);
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnect:scanforWi-Finetworks,andconnecttothestrongestofthenetworksabovedelay(250);Serial.print('.');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer
if(MDNS.begin("esp8266")){//StartthemDNSresponderforesp8266.localSerial.println("mDNSresponderstarted");}else{Serial.println("ErrorsettingupMDNSresponder!");}
server.on("/",HTTP_GET,handleRoot);//Callthe'handleRoot'functionwhenaclientrequestsURI"/"server.on("/LED",HTTP_POST,handleLED);//Callthe'handleLED'functionwhenaPOSTrequestismadetoURI"/LED"server.onNotFound(handleNotFound);//WhenaclientrequestsanunknownURI(i.e.somethingotherthan"/"),callfunction"handleNotFound"
server.begin();//ActuallystarttheserverSerial.println("HTTPserverstarted");}
voidloop(void){server.handleClient();//ListenforHTTPrequestsfromclients}
voidhandleRoot(){//WhenURI/isrequested,sendawebpagewithabuttontotoggletheLEDserver.send(200,"text/html","<formaction=\"/LED\"method=\"POST\"><inputtype=\"submit\"value=\"ToggleLED\"></form>");}
voidhandleLED(){//IfaPOSTrequestismadetoURI/LEDdigitalWrite(led,!digitalRead(led));//ChangethestateoftheLEDserver.sendHeader("Location","/");//Addaheadertorespondwithanewlocationforthebrowsertogotothehomepageagainserver.send(303);//SenditbacktothebrowserwithanHTTPstatus303(SeeOther)toredirect}
voidhandleNotFound(){server.send(404,"text/plain","404:Notfound");//SendHTTPstatus404(NotFound)whenthere'snohandlerfortheURIintherequest}
Asyoucansee,theserver.onfunctionnowtakesthreeparameters:theURI,therequestmethod(GETorPOST)andthefunctiontoexecute.
ConnectanLEDtoGPIO2,anduploadthesketch.Thengotohttp://esp8266.local/andclickthebuttontoturntheLEDonoroff.
YoucanopenthedeveloperoptionsinChrome(F12)tochecktheHTTPrequestthataremadewhenyouclickthebutton:you'llseethatitfirstsendaPOSTrequest,andthenreceivesa303(SeeOther)HTTPstatusasaresponse.TheresponsealsohasaLocationheadercontainingtheURI"/",sothebrowserwillsendaGETrequesttotheURIofthisnewlocation:
![Page 28: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/28.jpg)
Ifyoucheckthepagesource(CTRL+U),youcanseethesimpleHTMLformthat'sused:
<formaction="/LED"method="POST"><inputtype="submit"value="ToggleLED"></form>
SendingdatatotheESPusingHTTPPOSTInthepreviousexample,wesentanemptyPOSTrequesttotheESP8266.Inthepreviouschapterhowever,Iexplainedthatit'spossibletosendallkindsofdatainthebodyofthePOSTrequest.
Inthisexample,I'llshowyouhowtosendausernameandapasswordtotheESP.TheESPwillthencheckiftheyarecorrect,andrespondtotherequestwiththeappropriatepage.
#include<ESP8266WiFi.h>#include<WiFiClient.h>#include<ESP8266WiFiMulti.h>#include<ESP8266mDNS.h>#include<ESP8266WebServer.h>
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
ESP8266WebServerserver(80);//CreateawebserverobjectthatlistensforHTTPrequestonport80
voidhandleRoot();//functionprototypesforHTTPhandlersvoidhandleLogin();voidhandleNotFound();
voidsetup(void){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnect:scanforWi-Finetworks,andconnecttothestrongestofthenetworksabovedelay(250);Serial.print('.');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");
![Page 29: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/29.jpg)
Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer
if(MDNS.begin("esp8266")){//StartthemDNSresponderforesp8266.localSerial.println("mDNSresponderstarted");}else{Serial.println("ErrorsettingupMDNSresponder!");}
server.on("/",HTTP_GET,handleRoot);//Callthe'handleRoot'functionwhenaclientrequestsURI"/"server.on("/login",HTTP_POST,handleLogin);//Callthe'handleLogin'functionwhenaPOSTrequestismadetoURI"/login"server.onNotFound(handleNotFound);//WhenaclientrequestsanunknownURI(i.e.somethingotherthan"/"),callfunction"handleNotFound"
server.begin();//ActuallystarttheserverSerial.println("HTTPserverstarted");}
voidloop(void){server.handleClient();//ListenforHTTPrequestsfromclients}
voidhandleRoot(){//WhenURI/isrequested,sendawebpagewithabuttontotoggletheLEDserver.send(200,"text/html","<formaction=\"/login\"method=\"POST\"><inputtype=\"text\"name=\"username\"placeholder=\"Username\"></br><inputtype=\"password\"name=\"password\"placeholder=\"Password\"></br><inputtype=\"submit\"value=\"Login\"></form><p>Try'JohnDoe'and'password123'...</p>");}
voidhandleLogin(){//IfaPOSTrequestismadetoURI/loginif(!server.hasArg("username")||!server.hasArg("password")||server.arg("username")==NULL||server.arg("password")==NULL){//IfthePOSTrequestdoesn'thaveusernameandpassworddataserver.send(400,"text/plain","400:InvalidRequest");//Therequestisinvalid,sosendHTTPstatus400return;}if(server.arg("username")=="JohnDoe"&&server.arg("password")=="password123"){//Ifboththeusernameandthepasswordarecorrectserver.send(200,"text/html","<h1>Welcome,"+server.arg("username")+"!</h1><p>Loginsuccessful</p>");}else{//Usernameandpassworddon'tmatchserver.send(401,"text/plain","401:Unauthorized");}}
voidhandleNotFound(){server.send(404,"text/plain","404:Notfound");//SendHTTPstatus404(NotFound)whenthere'snohandlerfortheURIintherequest}
TheHTMLinhandleRootis:
<formaction="/login"method="POST"><inputtype="text"name="username"placeholder="Username"></br><inputtype="password"name="password"placeholder="Password"></br><inputtype="submit"value="Login"></form><p>Try'JohnDoe'and'password123'...</p>
Uploadthesketchandgotohttp://esp8266.local/,thentype'JohnDoe'intotheusernamefield,and'password123'intothepasswordfield,andclick'Login'.Youshouldgetawelcomescreen.Ifyouleaveonorbothofthefieldsblank,youshouldgeta400(BadRequest)error.Ifyouenterawrongusernameorpassword,youshouldgeta401(Unauthorized)error.
ThedataofthePOSTbodycanbeaccessedusingserver.arg("key"),andyoucancheckifaspecifickeyexistsusingserver.hasArg("key").ThekeynameontheESP8266correspondstothenameargumentintheHTMLformonthewebpage.
WhenwegetaPOSTrequest,wefirstcheckifthenecessaryarguments(usernameandpassword)arepresent.Ifthat'snotthecase,wesenda400(InvalidRequest)status.Thenwecheckifthecredentialsmatch'JohnDoe'&'password123'.Ifthat'sthecase,werespondwithastatus200(Ok)andawelcomepage.Iftheusernameand/orpassworddoesn'tmatch,wesenda401(Unauthorized)status.
InlinefunctionsInthepreviousexamples,wepassedhandleRootandhandleNotFoundtotheserver.onfunctionasaparameter(callbackfunction).Insomecaseshowever,it'smorereadabletojustwritethedefinitionofthefunctioninline,likeso:
voidsetup(){//...server.onNotFound([](){server.send(404,"text/plain","404:Notfound");});}
![Page 30: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/30.jpg)
SPIFlashFileSystemUpuntilnow,we'vealwaysincludedtheHTMLforourwebpagesasstringliteralsinoursketch.Thismakesourcodeveryhardtoread,andyou'llrunoutofmemoryratherquickly.Ifyouremembertheintroduction,ImentionedtheSerialPeripheralInterfaceFlashFileSystem,orSPIFFSforshort.It'salight-weightfilesystemformicrocontrollerswithanSPIflashchip.Theon-boardflashchipoftheESP8266hasplentyofspaceforyourwebpages,especiallyifyouhavethe1MB,2MBor4MBversion.
SPIFFSlet'syouaccesstheflashmemoryasifitwasanormalfilesystemliketheoneonyourcomputer(butmuchsimplerofcourse):youcanreadandwritefiles,createfolders...
TheeasiestwaytolearnhowtouseSPIFFSistolookatsomeexamples.Butafileserverwithnofilestoserveisprettypointless,soI'llexplainhowtouploadfilestotheSPIFFSfirst.
UploadingfilestoSPIFFSToselecttherightfilestoupload,youhavetoplacetheminafoldercalleddata,insidethesketchfolderofyourproject:OpenyoursketchintheArduinoIDE,andhitCTRL+K.Waitforafileexplorerwindowtoopen,andcreateanewfoldernameddata.Copyyourfilesovertothisfolder.(Onlyusesmallfilesliketextfilesoricons.There'snotenoughspaceforlargephotosorvideos.)Next,selectallfilesinthefolder(CTRL+A)andcheckthesizeofallfilescombined(don'tforgetsubfolders).GototheArduinoIDEagain,andunderTools>FlashSize,selectanoptionwiththerightflashsizeforyourboard,andaSPIFFSsizethatislargerthanthesizeofyourdatafolder.Thenuploadthesketch.Whenthat'sfinished,makesurethattheSerialMonitorisclosed,thenopentheToolsmenu,andclickESP8266sketchdataupload.IfyourESPhasauto-resetandauto-program,itshouldworkautomatically,ifyoudon'thaveauto-program,youhavetomanuallyenterprogrammodebeforeuploadingthedatatoSPIFFS.Theprocedureisexactlythesameasenteringprogrammodebeforeuploadingasketch.
IfyougetanerrorsayingSPIFFS_writeerror(-10001):Filesystemisfull,thismeansthatyourfilesaretoolargetofitintotheSPIFFSmemory.SelectalargerSPIFFSsizeunderTools>FlashSize,ordeletesomefiles.EvenifyourcomputersaysthatthefilesaresmallerthantheselectedSPIFFSsize,youcanstillgetthiserror:thishastodowithblocksizes,andmetadatalikefileandfoldernamesthattakeupspaceaswell.
IfyouchangetheSPIFFSsize,youhavetoreuploadyoursketch,becausewhenyouchangetheSPIFFSsize,thememorylocationwillbedifferent.TheprogramhastoknowtheupdatedSPIFFSaddressoffsettobeabletoreadthefiles.
SPIFFSFileServer
Thefollowingexampleisaverybasicfileserver:itjusttakestheURIoftheHTTPrequest,checksiftheURIpointstoafileintheSPIFFS,andifitfindsthefile,itsendsitasaresponse.
#include<ESP8266WiFi.h>#include<WiFiClient.h>#include<ESP8266WiFiMulti.h>#include<ESP8266mDNS.h>#include<ESP8266WebServer.h>#include<FS.h>//IncludetheSPIFFSlibrary
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
ESP8266WebServerserver(80);//CreateawebserverobjectthatlistensforHTTPrequestonport80
StringgetContentType(Stringfilename);//convertthefileextensiontotheMIMEtypeboolhandleFileRead(Stringpath);//sendtherightfiletotheclient(ifitexists)
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnectdelay(250);Serial.print('.');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer
if(MDNS.begin("esp8266")){//StartthemDNSresponderforesp8266.localSerial.println("mDNSresponderstarted");}else{Serial.println("ErrorsettingupMDNSresponder!");}
SPIFFS.begin();//StarttheSPIFlashFilesSystemserver.onNotFound([](){//IftheclientrequestsanyURIif(!handleFileRead(server.uri()))//senditifitexistsserver.send(404,"text/plain","404:NotFound");//otherwise,respondwitha404(NotFound)error});
server.begin();//ActuallystarttheserverSerial.println("HTTPserverstarted");}
voidloop(void){server.handleClient();}
![Page 31: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/31.jpg)
StringgetContentType(Stringfilename){//convertthefileextensiontotheMIMEtypeif(filename.endsWith(".html"))return"text/html";elseif(filename.endsWith(".css"))return"text/css";elseif(filename.endsWith(".js"))return"application/javascript";elseif(filename.endsWith(".ico"))return"image/x-icon";return"text/plain";}
boolhandleFileRead(Stringpath){//sendtherightfiletotheclient(ifitexists)Serial.println("handleFileRead:"+path);if(path.endsWith("/"))path+="index.html";//Ifafolderisrequested,sendtheindexfileStringcontentType=getContentType(path);//GettheMIMEtypeif(SPIFFS.exists(path)){//IfthefileexistsFilefile=SPIFFS.open(path,"r");//Openitsize_tsent=server.streamFile(file,contentType);//Andsendittotheclientfile.close();//Thenclosethefileagainreturntrue;}Serial.println("\tFileNotFound");returnfalse;//Ifthefiledoesn'texist,returnfalse}
Asyoucansee,wedon'tuseserver.oninthisexample.Instead,weuseserver.onNotFound:thiswillmatchanyURI,sincewedidn'tdeclareanyspecificURIhandlerslikeinthepreviousserverexamples.WhenaURIisrequested,wecallthefunctionhandleFileRead.ThisfunctionchecksiftheURIoftheHTTPrequestisthepathtoanexistingfileintheSPIFFS.Ifthat'sthecase,itsendsthefilebacktotheclient.Ifthepathdoesn'texist,itreturnsfalse,anda404(NotFound)HTTPstatuswillbesent.
TheMIMEtypeforthedifferentfilesisbasedonthefileextension.Youcouldaddotherfiletypesaswell.Forinstance:
StringgetContentType(Stringfilename){if(filename.endsWith(".htm"))return"text/html";elseif(filename.endsWith(".html"))return"text/html";elseif(filename.endsWith(".css"))return"text/css";elseif(filename.endsWith(".js"))return"application/javascript";elseif(filename.endsWith(".png"))return"image/png";elseif(filename.endsWith(".gif"))return"image/gif";elseif(filename.endsWith(".jpg"))return"image/jpeg";elseif(filename.endsWith(".ico"))return"image/x-icon";elseif(filename.endsWith(".xml"))return"text/xml";elseif(filename.endsWith(".pdf"))return"application/x-pdf";elseif(filename.endsWith(".zip"))return"application/x-zip";elseif(filename.endsWith(".gz"))return"application/x-gzip";return"text/plain";}
ThisexampleisadaptedfromtheFSBrowserexamplebyHristoGochkov.
CompressingfilesTheESP8266'sflashmemoryisn'thuge,andmosttextfiles,likehtml,cssetc.canbecompressedbyquitealargefactor.Modernwebbrowsersacceptcompressedfilesasaresponse,sowe'lltakeadvantageofthisbyuploadingcompressedversionsofourhtmlandiconfilestotheSPIFFS,inordertosavespaceandbandwidth.
Todothis,weneedtoaddtheGNUzipfiletypetoourlistofMIMEtypes:
StringgetContentType(Stringfilename){if(filename.endsWith(".html"))return"text/html";elseif(filename.endsWith(".css"))return"text/css";elseif(filename.endsWith(".js"))return"application/javascript";elseif(filename.endsWith(".ico"))return"image/x-icon";elseif(filename.endsWith(".gz"))return"application/x-gzip";return"text/plain";}
AndweneedtochangeourhandleFileReadfunctionaswell:
boolhandleFileRead(Stringpath){//sendtherightfiletotheclient(ifitexists)Serial.println("handleFileRead:"+path);if(path.endsWith("/"))path+="index.html";//Ifafolderisrequested,sendtheindexfileStringcontentType=getContentType(path);//GettheMIMEtypeStringpathWithGz=path+".gz";if(SPIFFS.exists(pathWithGz)||SPIFFS.exists(path)){//Ifthefileexists,eitherasacompressedarchive,ornormalif(SPIFFS.exists(pathWithGz))//Ifthere'sacompressedversionavailablepath+=".gz";//UsethecompressedversionFilefile=SPIFFS.open(path,"r");//Openthefilesize_tsent=server.streamFile(file,contentType);//Sendittotheclientfile.close();//ClosethefileagainSerial.println(String("\tSentfile:")+path);returntrue;}Serial.println(String("\tFileNotFound:")+path);returnfalse;//Ifthefiledoesn'texist,returnfalse}
Now,trycompressingsomeofthefilestotheGNUzipformat(.gz),anduploadingthemtoSPIFFS.Oryoucanjustdownloadthenewdatafolder(unzipitfirst).Everytimeaclientrequestsacertainfile,theESPwillcheckifacompressedversionisavailable.Ifso,itwillusethatinsteadoftheuncompressedfile.TheoutputintheSerialMonitorshouldlooksomethinglikethis:
handleFileRead:/ Sentfile:/index.html.gzhandleFileRead:/main.css Sentfile:/main.csshandleFileRead:/JavaScript.js Sentfile:/JavaScript.jshandleFileRead:/folder/JavaScript.js Sentfile:/folder/JavaScript.jshandleFileRead:/favicon.ico Sentfile:/favicon.ico.gz
![Page 32: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/32.jpg)
Itautomaticallydetectedthatithadtosendthecompressedversionsofindex.htmlandfavicon.ico.
![Page 33: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/33.jpg)
UploadingfilestotheserverTherearescenarioswhereyoumaywanttouploadnewfilestotheserverfromwithinabrowser,withouthavingtoconnecttotheESP8266overUSBinordertoflashanewSPIFFSimage.Inthischapter,I'llshowyouhowtouseHTMLformsandPOSTrequeststouploadoreditfilestoourlittleESPserver.
Client:HTMLformTheeasiestwaytouploadfilesisbyusinganHTMLform,justlikeinthefirstserverexamples,whereweusedformstoturnon/offLEDs,andtosendthelogincredentialsbacktotheserver.Ifyouchooseafileinput,youautomaticallygetafilepicker,andthebrowserwillsendtherightPOSTrequesttotheserver,withthefileattached.
<formmethod="post"enctype="multipart/form-data"><inputtype="file"name="name"><inputclass="button"type="submit"value="Upload"></form>
Server
IntheESPcode,wehavetoaddahandlertoourserverthathandlesPOSTrequeststothe/uploadURI.WhenitreceivesaPOSTrequest,itsendsastatus200(OK)backtotheclienttostartreceivingthefile,andthenwriteittotheSPIFFS.Whenthefileisuploadedsuccessfully,itredirectstheclienttoasuccesspage.TherelevantnewcodeisfoundinthesetupandthehandleFileUploadfunction.
#include<ESP8266WiFi.h>#include<WiFiClient.h>#include<ESP8266WiFiMulti.h>#include<ESP8266mDNS.h>#include<ESP8266WebServer.h>#include<FS.h>//IncludetheSPIFFSlibrary
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
ESP8266WebServerserver(80);//CreateawebserverobjectthatlistensforHTTPrequestonport80
FilefsUploadFile;//aFileobjecttotemporarilystorethereceivedfile
StringgetContentType(Stringfilename);//convertthefileextensiontotheMIMEtypeboolhandleFileRead(Stringpath);//sendtherightfiletotheclient(ifitexists)voidhandleFileUpload();//uploadanewfiletotheSPIFFS
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnectdelay(1000);Serial.print(++i);Serial.print('');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer
if(!MDNS.begin("esp8266")){//StartthemDNSresponderforesp8266.localSerial.println("ErrorsettingupMDNSresponder!");}Serial.println("mDNSresponderstarted");
SPIFFS.begin();//StarttheSPIFlashFilesSystem
server.on("/upload",HTTP_GET,[](){//iftheclientrequeststheuploadpageif(!handleFileRead("/upload.html"))//senditifitexistsserver.send(404,"text/plain","404:NotFound");//otherwise,respondwitha404(NotFound)error});
server.on("/upload",HTTP_POST,//iftheclientpoststotheuploadpage[](){server.send(200);},//Sendstatus200(OK)totelltheclientwearereadytoreceivehandleFileUpload//Receiveandsavethefile);
server.onNotFound([](){//IftheclientrequestsanyURIif(!handleFileRead(server.uri()))//senditifitexistsserver.send(404,"text/plain","404:NotFound");//otherwise,respondwitha404(NotFound)error});
server.begin();//ActuallystarttheserverSerial.println("HTTPserverstarted");}
voidloop(){server.handleClient();}
StringgetContentType(Stringfilename){//convertthefileextensiontotheMIMEtypeif(filename.endsWith(".html"))return"text/html";elseif(filename.endsWith(".css"))return"text/css";elseif(filename.endsWith(".js"))return"application/javascript";elseif(filename.endsWith(".ico"))return"image/x-icon";elseif(filename.endsWith(".gz"))return"application/x-gzip";return"text/plain";}
![Page 34: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/34.jpg)
boolhandleFileRead(Stringpath){//sendtherightfiletotheclient(ifitexists)Serial.println("handleFileRead:"+path);if(path.endsWith("/"))path+="index.html";//Ifafolderisrequested,sendtheindexfileStringcontentType=getContentType(path);//GettheMIMEtypeStringpathWithGz=path+".gz";if(SPIFFS.exists(pathWithGz)||SPIFFS.exists(path)){//Ifthefileexists,eitherasacompressedarchive,ornormalif(SPIFFS.exists(pathWithGz))//Ifthere'sacompressedversionavailablepath+=".gz";//UsethecompressedverionFilefile=SPIFFS.open(path,"r");//Openthefilesize_tsent=server.streamFile(file,contentType);//Sendittotheclientfile.close();//ClosethefileagainSerial.println(String("\tSentfile:")+path);returntrue;}Serial.println(String("\tFileNotFound:")+path);//Ifthefiledoesn'texist,returnfalsereturnfalse;}
voidhandleFileUpload(){//uploadanewfiletotheSPIFFSHTTPUpload&upload=server.upload();if(upload.status==UPLOAD_FILE_START){Stringfilename=upload.filename;if(!filename.startsWith("/"))filename="/"+filename;Serial.print("handleFileUploadName:");Serial.println(filename);fsUploadFile=SPIFFS.open(filename,"w");//OpenthefileforwritinginSPIFFS(createifitdoesn'texist)filename=String();}elseif(upload.status==UPLOAD_FILE_WRITE){if(fsUploadFile)fsUploadFile.write(upload.buf,upload.currentSize);//Writethereceivedbytestothefile}elseif(upload.status==UPLOAD_FILE_END){if(fsUploadFile){//IfthefilewassuccessfullycreatedfsUploadFile.close();//ClosethefileagainSerial.print("handleFileUploadSize:");Serial.println(upload.totalSize);server.sendHeader("Location","/success.html");//Redirecttheclienttothesuccesspageserver.send(303);}else{server.send(500,"text/plain","500:couldn'tcreatefile");}}}
ThehandleFileUploadfunctionjustwritesthefileattachedtothePOSTrequesttoSPIFFS.
Ifyouwantouseotherfiletypesaswell,youcanjustaddthemtothegetContentTypefunction.
UploadingfilesTouploadanewfiletotheESP,ortoupdateanexistingfile,justgotohttp://esp8266.local/upload,clicktheChooseFilebutton,selectthefileyouwishtoupload,andclickUpload.YoucannowentertheURLintotheURLbar,andopenthenewfile.
Anoteonsafety
Thisexampleisn'tverysecure(obviously).EveryonethatcanconnecttotheESPcanuploadnewfiles,oredittheexistingfilesandinsertXSScode,forexample.There'salsonotalotoferrorchecking/handling,likecheckingifthere'senoughspaceintheSPIFFStouploadanewfile,etc.
AdvancedexampleThecodefortheseSPIFFSserverexamplescomes(forthemostpart)fromanexamplewrittenbyHristoGochkov.YoucanfinditunderFile>Examples>ESP8266WebServer>FSBrowser.Ithasawebinterfaceforbrowsingandeditingfilesinyourbrowser,andhassomeothernicefeaturesaswell.
![Page 35: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/35.jpg)
OverTheAirUpdatesUploadingoverSerialisfineduringdevelopment,whenyouhaveaccesstotheSerialpinsandtheUSBport.Butonceyourprojectisfinished,andyouputitinsideanenclosure,itnotthateasytouploadupdateswithbugfixesornewfeatures.AsolutiontothisproblemisOverTheAirupdating,orOTAforshort.Asthenameimplies,thistechnologyallowsyoutouploadnewcodeoverWi-Fi,insteadofSerial.Theonlydisadvantageisthatyouhavetoexplicitlyaddthecodeforittoeverysketchyouupload.Youalsoneedaflashchipthatistwicethesizeofyoursketch,soitwon'tworkfor512kBboards.(Ithastodownloadthenewsketchwhilestillrunningtheoldcode.)Let'stakealookatanexample...
BlinkOTAThefollowingexampleisbasicallyBlinkWithoutDelay,butwiththenecessaryOTAandWi-Ficodeaddedaswell.
#include<ESP8266WiFi.h>#include<ESP8266WiFiMulti.h>#include<ArduinoOTA.h>
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
constbyteled=13;
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnectdelay(250);Serial.print('.');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputerArduinoOTA.setHostname("ESP8266");ArduinoOTA.setPassword("esp8266");
ArduinoOTA.onStart([](){Serial.println("Start");});ArduinoOTA.onEnd([](){Serial.println("\nEnd");});ArduinoOTA.onProgress([](unsignedintprogress,unsignedinttotal){Serial.printf("Progress:%u%%\r",(progress/(total/100)));});ArduinoOTA.onError([](ota_error_terror){Serial.printf("Error[%u]:",error);if(error==OTA_AUTH_ERROR)Serial.println("AuthFailed");elseif(error==OTA_BEGIN_ERROR)Serial.println("BeginFailed");elseif(error==OTA_CONNECT_ERROR)Serial.println("ConnectFailed");elseif(error==OTA_RECEIVE_ERROR)Serial.println("ReceiveFailed");elseif(error==OTA_END_ERROR)Serial.println("EndFailed");});ArduinoOTA.begin();Serial.println("OTAready");
pinMode(led,OUTPUT);digitalWrite(led,1);}
unsignedlongpreviousTime=millis();
constunsignedlonginterval=1000;
voidloop(){ArduinoOTA.handle();unsignedlongdiff=millis()-previousTime;if(diff>interval){digitalWrite(led,!digitalRead(led));//ChangethestateoftheLEDpreviousTime+=diff;}}
AddyourWi-Ficredentials,anduploadthesketchoverSerial.ConnectanLED(+resistor)topin13.ThenrestarttheIDE(youhavetocloseallwindows).GotoTools>Port,andyoushouldgetanewoption:NetworkPorts:ESP8266at192.168.1.x.Selectit.
![Page 36: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/36.jpg)
Next,changetheintervalonline59from1000to500milliseconds,andclickupload.Youshouldgetapasswordprompt:enter"esp8266".Thispasswordissetonline31,soyoucanchangeitifyouwantto.Youcanalsodeleteline31altogethertouseitwithoutapassword,butit'snotrecommended-forobvioussecurityreasons.
Thesketchshoulduploadjustfine,andoncetheESPhasresetitself,theLEDshouldblinktwiceasfast.
Onceinawhile,youmightgetanerrorsaying[ERROR]:NoAnswer.Ifthishappens,justenterthepassword,andtryagain.
SerialMonitorOTAUsingtheSerialMonitoroverWi-Fiisnotpossible(yet?).Whenyoutrytoopenit,you'llbepromptedapassword,enteringthepasswordwon'twork,becausethereisnoSSHsupporttoaccesstheESP'sconsole.
YoucanuseadifferentprogramtogetdebugoutputfromthephysicalSerialport.OnWindows,youcantryPortmon.OnLinux,youcantryGTKTerm(sudoapt-getinstallgtkterm)orScreen(sudoapt-getinstallscreentoinstall,andscreen/dev/ttyUSB0115200orscreen/dev/ttyACM0115200torun;CTRL+A,CTRL+Dtoexit).
![Page 37: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/37.jpg)
WebSocketcommunicationUpuntilnow,we'vealwaysusedlinks(GET)andHTMLforms(POST)togetdatafromtheESP,ortosenddatatoit.Thisalwaysresultedinabrowsernavigationaction.TherearemanysituationswhereyouwanttosenddatatotheESPwithoutrefreshingthepage.
OnewaytodothisisbyusingAJAXandXMLHTTPrequests.ThedisadvantageisthatyouhavetoestablishanewTCPconnectionforeverymessageyousend.Thisaddsaloadoflatency.WebSocketisatechnologythatkeepstheTCPconnectionopen,soyoucanconstantlysenddatabackandforthbetweentheESPandtheclient,withlowlatency.Andsinceit'sTCP,you'resurethatthepacketswillarriveintact.
ControllingRGBLEDsfromawebinterfaceusingWebSocketTolearnhowtouseWebSockets,Icreatedthiscomprehensiveexample,itusesprettymucheverythingwe'vecoveredsofar.
TheESPhostsawebpagewiththreesliderstosetthered,greenandbluelevelsofanRGBLED(orLEDstrip).There'salsoabuttontoturnonarainboweffectthatcyclesthroughtheentirecolorwheel.ColordataistransmittedfromthebrowsertotheESPviaaWebSocketconnection.YoucanconnecttotheESPdirectly,usingitasanAP,orlettheESPconnecttoadifferentAP.YoucanusemDNStoopenthewebpage,bybrowsingtohttp://esp8266.local.AllfilesarestoredintheESP'sSPIFFS,andyoucanuploadnewfiles,orupdatefilesviaawebinterface.YoucanalsousetheOTAservicetouploadnewfirmware(sketches)overWi-Fi.
Improvingreadability
Whendealingwithlargeandcomplicatedprograms,it'sagoodideatomakeabstractionofsomethings,andcreatefunctionswithadescriptivenameinsteadofendlesslinesofmeaninglesscode.
Evenifyouhavelotsofcommentsinyourcode,it'llbeveryhardtopreserveanoverview.Usingfunctionswillgreatlyimprovethereadabilityofyourcode.Sojustsplitupthecodeintodifferentpartsandmoveallpiecestofunctionsatthebottomofyoursketch,oreventodifferentfiles.
Inthefollowingexample,thesetupwasverylongandcluttered,soIsplititupintoseveraldifferentfunctions:onetoconnecttotheWi-Fi,onetostarttheOTAupdateservice,onetostarttheSPIFFS...andsoon.
DownloadingWebSocketsforArduino
We'llbeusingthearduinoWebSocketslibrarybyLinks2004.DownloaditfromGitHubandinstallit.(Sketch>IncludeLibrary>Add.ZIPLibrary...)
Libraries,constantsandglobals
Atthetopofthesketchwe'llincludethenecessarylibraries,createsomeglobalserverandfileobjectslikeinthepreviousexamples,andsomeconstantsforthehostname,APssid,passwords,LEDpins...
#include<ESP8266WiFi.h>#include<ESP8266WiFiMulti.h>#include<ArduinoOTA.h>#include<ESP8266WebServer.h>#include<ESP8266mDNS.h>#include<FS.h>#include<WebSocketsServer.h>
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
ESP8266WebServerserver=ESP8266WebServer(80);//createawebserveronport80WebSocketsServerwebSocket=WebSocketsServer(81);//createawebsocketserveronport81
FilefsUploadFile;//aFilevariabletotemporarilystorethereceivedfile
constchar*ssid="ESP8266AccessPoint";//ThenameoftheWi-Finetworkthatwillbecreatedconstchar*password="thereisnospoon";//Thepasswordrequiredtoconnecttoit,leaveblankforanopennetwork
constchar*OTAName="ESP8266";//AnameandapasswordfortheOTAserviceconstchar*OTAPassword="esp8266";
#defineLED_RED15//specifythepinswithanRGBLEDconnected#defineLED_GREEN12#defineLED_BLUE13
constchar*mdnsName="esp8266";//DomainnameforthemDNSresponder
Youshouldalreadybefamiliarwithmostofthiscode.TheonlynewpartistheWebSocketserverlibrarythatisincluded,andtheWebSocketserverobject,butthisshouldn'tbeaproblem.
Setup
voidsetup(){pinMode(LED_RED,OUTPUT);//thepinswithLEDsconnectedareoutputspinMode(LED_GREEN,OUTPUT);pinMode(LED_BLUE,OUTPUT);
Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println("\r\n");
startWiFi();//StartaWi-Fiaccesspoint,andtrytoconnecttosomegivenaccesspoints.ThenwaitforeitheranAPorSTAconnectionstartOTA();//StarttheOTAservice
![Page 38: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/38.jpg)
startSPIFFS();//StarttheSPIFFSandlistallcontents
startWebSocket();//StartaWebSocketserverstartMDNS();//StartthemDNSresponder
startServer();//StartaHTTPserverwithafilereadhandlerandanuploadhandler}
Asyoucansee,thesetupisnowmuchmorecondensedandgivesamuchbetteroverviewofwhatit'sdoing.Tounderstandtheprogram,youdon'thavetoknoweachindividualstepthatisrequiredtoconnecttoaWi-Finetwork,it'senoughtoknowthatitwillconnecttoaWi-Finetwork,becausethat'swhatthestartWiFifunctiondoes.
Loop
boolrainbow=false;//Therainboweffectisturnedoffonstartup
unsignedlongprevMillis=millis();inthue=0;
voidloop(){webSocket.loop();//constantlycheckforwebsocketeventsserver.handleClient();//runtheserverArduinoOTA.handle();//listenforOTAevents
if(rainbow){//iftherainboweffectisturnedonif(millis()>prevMillis+32){if(++hue==360)//Cyclethroughthecolorwheel(incrementbyonedegreeevery32ms)hue=0;setHue(hue);//SettheRGBLEDtotherightcolorprevMillis=millis();}}}
Samegoesfortheloop:mostoftheworkisdonebythefirstthreefunctionsthathandletheWebSocketcommunication,HTTPrequestsandOTAupdates.Whensuchaneventhappens,theappropriatehandlerfunctionswillbeexecuted.Thesearedefinedelsewhere.
Thesecondpartistherainboweffect.Ifitisturnedon,itcyclesthroughthecolorwheelandsetsthecolortotheRGBLED.Ifyoudon'tunderstandwhyIusemillis(),youcantakealookattheBlinkWithoutDelayexample.
Setupfunctions
voidstartWiFi(){//StartaWi-Fiaccesspoint,andtrytoconnecttosomegivenaccesspoints.ThenwaitforeitheranAPorSTAconnectionWiFi.softAP(ssid,password);//StarttheaccesspointSerial.print("AccessPoint\"");Serial.print(ssid);Serial.println("\"started\r\n");
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting");while(wifiMulti.run()!=WL_CONNECTED&&WiFi.softAPgetStationNum()<1){//WaitfortheWi-Fitoconnectdelay(250);Serial.print('.');}Serial.println("\r\n");if(WiFi.softAPgetStationNum()==0){//IftheESPisconnectedtoanAPSerial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.print(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputer}else{//IfastationisconnectedtotheESPSoftAPSerial.print("StationconnectedtoESP8266AP");}Serial.println("\r\n");}
voidstartOTA(){//StarttheOTAserviceArduinoOTA.setHostname(OTAName);ArduinoOTA.setPassword(OTAPassword);
ArduinoOTA.onStart([](){Serial.println("Start");digitalWrite(LED_RED,0);//turnofftheLEDsdigitalWrite(LED_GREEN,0);digitalWrite(LED_BLUE,0);});ArduinoOTA.onEnd([](){Serial.println("\r\nEnd");});ArduinoOTA.onProgress([](unsignedintprogress,unsignedinttotal){Serial.printf("Progress:%u%%\r",(progress/(total/100)));});ArduinoOTA.onError([](ota_error_terror){Serial.printf("Error[%u]:",error);if(error==OTA_AUTH_ERROR)Serial.println("AuthFailed");elseif(error==OTA_BEGIN_ERROR)Serial.println("BeginFailed");elseif(error==OTA_CONNECT_ERROR)Serial.println("ConnectFailed");elseif(error==OTA_RECEIVE_ERROR)Serial.println("ReceiveFailed");elseif(error==OTA_END_ERROR)Serial.println("EndFailed");});ArduinoOTA.begin();Serial.println("OTAready\r\n");}
voidstartSPIFFS(){//StarttheSPIFFSandlistallcontentsSPIFFS.begin();//StarttheSPIFlashFileSystem(SPIFFS)Serial.println("SPIFFSstarted.Contents:");{Dirdir=SPIFFS.openDir("/");
![Page 39: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/39.jpg)
while(dir.next()){//ListthefilesystemcontentsStringfileName=dir.fileName();size_tfileSize=dir.fileSize();Serial.printf("\tFSFile:%s,size:%s\r\n",fileName.c_str(),formatBytes(fileSize).c_str());}Serial.printf("\n");}}
voidstartWebSocket(){//StartaWebSocketserverwebSocket.begin();//startthewebsocketserverwebSocket.onEvent(webSocketEvent);//ifthere'sanincommingwebsocketmessage,gotofunction'webSocketEvent'Serial.println("WebSocketserverstarted.");}
voidstartMDNS(){//StartthemDNSresponderMDNS.begin(mdnsName);//startthemulticastdomainnameserverSerial.print("mDNSresponderstarted:http://");Serial.print(mdnsName);Serial.println(".local");}
voidstartServer(){//StartaHTTPserverwithafilereadhandlerandanuploadhandlerserver.on("/edit.html",HTTP_POST,[](){//IfaPOSTrequestissenttothe/edit.htmladdress,server.send(200,"text/plain","");},handleFileUpload);//goto'handleFileUpload'
server.onNotFound(handleNotFound);//ifsomeonerequestsanyotherfileorpage,gotofunction'handleNotFound'//andcheckifthefileexists
server.begin();//starttheHTTPserverSerial.println("HTTPserverstarted.");}
Thesearethefunctiondefinitionsofthefunctionsusedinthesetup.Nothingnewhere,apartfromthestartWebSocketfunction.YoujusthavetostarttheWebSocketserverusingthebeginmethod,andthengiveitacallbackfunctionthatisexecutedwhentheESPreceivesaWebSocketmessage.
Serverhandlers
Thisisthecodethatisexecutedoncertainserver-relatedevents,likewhenanHTTPrequestisreceived,whenafileisbeinguploaded,whenthere'sanincomingWebSocketmessage...etc.
voidhandleNotFound(){//iftherequestedfileorpagedoesn'texist,returna404notfounderrorif(!handleFileRead(server.uri())){//checkifthefileexistsintheflashmemory(SPIFFS),ifso,senditserver.send(404,"text/plain","404:FileNotFound");}}
boolhandleFileRead(Stringpath){//sendtherightfiletotheclient(ifitexists)Serial.println("handleFileRead:"+path);if(path.endsWith("/"))path+="index.html";//Ifafolderisrequested,sendtheindexfileStringcontentType=getContentType(path);//GettheMIMEtypeStringpathWithGz=path+".gz";if(SPIFFS.exists(pathWithGz)||SPIFFS.exists(path)){//Ifthefileexists,eitherasacompressedarchive,ornormalif(SPIFFS.exists(pathWithGz))//Ifthere'sacompressedversionavailablepath+=".gz";//UsethecompressedverionFilefile=SPIFFS.open(path,"r");//Openthefilesize_tsent=server.streamFile(file,contentType);//Sendittotheclientfile.close();//ClosethefileagainSerial.println(String("\tSentfile:")+path);returntrue;}Serial.println(String("\tFileNotFound:")+path);//Ifthefiledoesn'texist,returnfalsereturnfalse;}
voidhandleFileUpload(){//uploadanewfiletotheSPIFFSHTTPUpload&upload=server.upload();Stringpath;if(upload.status==UPLOAD_FILE_START){path=upload.filename;if(!path.startsWith("/"))path="/"+path;if(!path.endsWith(".gz")){//ThefileserveralwaysprefersacompressedversionofafileStringpathWithGz=path+".gz";//Soifanuploadedfileisnotcompressed,theexistingcompressedif(SPIFFS.exists(pathWithGz))//versionofthatfilemustbedeleted(ifitexists)SPIFFS.remove(pathWithGz);}Serial.print("handleFileUploadName:");Serial.println(path);fsUploadFile=SPIFFS.open(path,"w");//OpenthefileforwritinginSPIFFS(createifitdoesn'texist)path=String();}elseif(upload.status==UPLOAD_FILE_WRITE){if(fsUploadFile)fsUploadFile.write(upload.buf,upload.currentSize);//Writethereceivedbytestothefile}elseif(upload.status==UPLOAD_FILE_END){if(fsUploadFile){//IfthefilewassuccessfullycreatedfsUploadFile.close();//ClosethefileagainSerial.print("handleFileUploadSize:");Serial.println(upload.totalSize);server.sendHeader("Location","/success.html");//Redirecttheclienttothesuccesspageserver.send(303);}else{server.send(500,"text/plain","500:couldn'tcreatefile");}}}
voidwebSocketEvent(uint8_tnum,WStype_ttype,uint8_t*payload,size_tlenght){//WhenaWebSocketmessageisreceivedswitch(type){caseWStype_DISCONNECTED://ifthewebsocketisdisconnectedSerial.printf("[%u]Disconnected!\n",num);break;caseWStype_CONNECTED:{//ifanewwebsocketconnectionisestablishedIPAddressip=webSocket.remoteIP(num);Serial.printf("[%u]Connectedfrom%d.%d.%d.%durl:%s\n",num,ip[0],ip[1],ip[2],ip[3],payload);rainbow=false;//Turnrainbowoffwhenanewconnectionisestablished}break;caseWStype_TEXT://ifnewtextdataisreceivedSerial.printf("[%u]getText:%s\n",num,payload);if(payload[0]=='#'){//wegetRGBdata
![Page 40: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/40.jpg)
uint32_trgb=(uint32_t)strtol((constchar*)&payload[1],NULL,16);//decodergbdataintr=((rgb>>20)&0x3FF);//10bitspercolor,soR:bits20-29intg=((rgb>>10)&0x3FF);//G:bits10-19intb=rgb&0x3FF;//B:bits0-9
analogWrite(LED_RED,r);//writeittotheLEDoutputpinsanalogWrite(LED_GREEN,g);analogWrite(LED_BLUE,b);}elseif(payload[0]=='R'){//thebrowsersendsanRwhentherainboweffectisenabledrainbow=true;}elseif(payload[0]=='N'){//thebrowsersendsanNwhentherainboweffectisdisabledrainbow=false;}break;}}
Again,mostofthecodeisadaptedfromthepreviousexamples,onlytheWebSocketpartisnew.
TherearedifferenttypesofWebSocketmessages,butwe'reonlyinterestedinthetexttype,becausetheJavaScriptcodeattheclientsidesendsthecolordataintextformat,asahexadecimalnumber,startingwitha'#'sign.Eachcolorisa10-bitnumber,sointotal,itgivesusa30-bitnumberfortheRGBvalue.
Whentherainbowfunctionisenabled,JavaScriptsendsan'R'character,andwhenit'sdisabled,itsendsa'N'character.
Let'stakealookattheHTMLandJavaScriptcodeaswell:
HTML
<!DOCTYPEhtml><html><head><title>LEDControl</title><linkhref='https://fonts.googleapis.com/css?family=Roboto:300'rel='stylesheet'type='text/css'><linkhref='main.css'rel='stylesheet'type='text/css'><linkrel="apple-touch-icon"sizes="180x180"href="/apple-touch-icon-180x180.png"><linkrel="icon"type="image/png"sizes="144x144"href="/favicon-144x144.png"><linkrel="icon"type="image/png"sizes="48x48"href="/favicon.ico"><linkrel="manifest"href="/manifest.json"><metaname="theme-color"content="#00878f"><metacontent='width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0'name='viewport'><scriptsrc="WebSocket.js"type="text/javascript"></script></head>
<body><center><header><h1>LEDControl</h1></header><div><table><tr><tdstyle="width:14.4px;text-align:right">R:</td><td><inputclass="enabled"id="r"type="range"min="0"max="1023"step="1"oninput="sendRGB();"value="0"></td></tr><tr><tdstyle="width:14.4px;text-align:right">G:</td><td><inputclass="enabled"id="g"type="range"min="0"max="1023"step="1"oninput="sendRGB();"value="0"></td></tr><tr><tdstyle="width:14.4px;text-align:right">B:</td><td><inputclass="enabled"id="b"type="range"min="0"max="1023"step="1"oninput="sendRGB();"value="0"></td></tr></table><pstyle="margin:8px0px"><buttonid="rainbow"class="button"style="background-color:#999"onclick="rainbowEffect();">Rainbow</button></p></div></center></body></html>
There'sreallynotmuchtoit,just3slidersandabuttonlinkedtoJavaScriptfunctions.
JavaScript
varrainbowEnable=false;varconnection=newWebSocket('ws://'+location.hostname+':81/',['arduino']);connection.onopen=function(){connection.send('Connect'+newDate());};connection.onerror=function(error){console.log('WebSocketError',error);};connection.onmessage=function(e){console.log('Server:',e.data);};connection.onclose=function(){console.log('WebSocketconnectionclosed');};
functionsendRGB(){varr=document.getElementById('r').value**2/1023;varg=document.getElementById('g').value**2/1023;varb=document.getElementById('b').value**2/1023;
varrgb=r<<20|g<<10|b;varrgbstr='#'+rgb.toString(16);console.log('RGB:'+rgbstr);connection.send(rgbstr);}
functionrainbowEffect(){rainbowEnable=!rainbowEnable;if(rainbowEnable){
![Page 41: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/41.jpg)
connection.send("R");document.getElementById('rainbow').style.backgroundColor='#00878F';document.getElementById('r').className='disabled';document.getElementById('g').className='disabled';document.getElementById('b').className='disabled';document.getElementById('r').disabled=true;document.getElementById('g').disabled=true;document.getElementById('b').disabled=true;}else{connection.send("N");document.getElementById('rainbow').style.backgroundColor='#999';document.getElementById('r').className='enabled';document.getElementById('g').className='enabled';document.getElementById('b').className='enabled';document.getElementById('r').disabled=false;document.getElementById('g').disabled=false;document.getElementById('b').disabled=false;sendRGB();}}
WejustcreateaWebSocketconnectionobjecttosenddatatotheESP.Theneverytimeasliderismoved,wetakethevaluesofthethreeslidersandwesquarethecolorvaluestogetasmootherandmorenaturalcurve.Wethencombinethemintoa30-bitnumber(10bitspercolor).Finally,theRGBvaluegetsconvertedtoahexadecimalstring,a'#'isadded,andit'ssenttotheESP.Whentherainbowbuttonispressed,theslidersaredisabled,andan'R'issenttotheESP.Whentherainbowbuttonispressedagain,theslidersareenabled,andan'N'issent.
Helperfunctions
BacktotheESP8266Arduinocodeagain.Weneedsomeotherfunctionsaswell,toconvertbytestoKBandMB,todeterminefiletypesbasedonfileextensionsandtoconvertahueangletoRGBvalues.
StringformatBytes(size_tbytes){//convertsizesinbytestoKBandMBif(bytes<1024){returnString(bytes)+"B";}elseif(bytes<(1024*1024)){returnString(bytes/1024.0)+"KB";}elseif(bytes<(1024*1024*1024)){returnString(bytes/1024.0/1024.0)+"MB";}}
StringgetContentType(Stringfilename){//determinethefiletypeofagivenfilename,basedontheextensionif(filename.endsWith(".html"))return"text/html";elseif(filename.endsWith(".css"))return"text/css";elseif(filename.endsWith(".js"))return"application/javascript";elseif(filename.endsWith(".ico"))return"image/x-icon";elseif(filename.endsWith(".gz"))return"application/x-gzip";return"text/plain";}
voidsetHue(inthue){//SettheRGBLEDtoagivenhue(color)(0°=Red,120°=Green,240°=Blue)hue%=360;//hueisananglebetween0and359°floatradH=hue*3.142/180;//Convertdegreestoradiansfloatrf,gf,bf;if(hue>=0&&hue<120){//ConvertfromHSIcolorspacetoRGBrf=cos(radH*3/4);gf=sin(radH*3/4);bf=0;}elseif(hue>=120&&hue<240){radH-=2.09439;gf=cos(radH*3/4);bf=sin(radH*3/4);rf=0;}elseif(hue>=240&&hue<360){radH-=4.188787;bf=cos(radH*3/4);rf=sin(radH*3/4);gf=0;}intr=rf*rf*1023;intg=gf*gf*1023;intb=bf*bf*1023;analogWrite(LED_RED,r);//WritetherightcolortotheLEDoutputpinsanalogWrite(LED_GREEN,g);analogWrite(LED_BLUE,b);}
ToconvertfromhuetoRGB,weusesinesandcosines,becausethesumoftheirsquaresisalwaysone,sothetotalintensitywillalwaysbemoreorlessthesame.
ThisresultsinthefollowingRGBcurves:
![Page 42: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/42.jpg)
UsingtheexampleDownloadtheexamplefromGitHubandopenitintheArduinoIDE.ThenaddyourWi-Ficredentials(lines83-85).ConnectanRGBLEDwithredtopin15,greentopin12andbluetopin13.Don'tforgetthecurrentlimitingresistors!SelecttheSPIFFSsize(64KBshouldbeenough,butifyouwanttouploadmorefileslater,youshouldsetithigher).UploadthesketchoverSerial,andthenuploadtheSPIFFSfilesusingTools>ESP8266SketchDataUpload.
WaitforittoconnecttoaWi-Finetwork,orconnecttotheESP8266AccessPointusingthepassword'thereisnospoon',andgotohttp://esp8266.local.Youshouldgetapagethatlookslikethis:
UsethesliderstoadjustthecolorlevelsoftheLED,andpresstheRainbowbuttontoenabletherainboweffect.
Ifyougotohttp://esp8266.local/edit.html,youcanuploadorupdatefiles:
![Page 43: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/43.jpg)
NetworkTimeProtocolTherearemanyapplicationswhereyouwanttoknowthetime.InanormalArduinoproject,youwouldhavetogetaRTCmodule,settherighttime,sacrificesomeArduinopinsforcommunication...AndwhentheRTCbatteryrunsout,youhavetoreplaceit.
OntheESP8266,allyouneedisanInternetconnection:youcanjustaskatimeserverwhattimeitis.Todothis,theNetworkTimeProtocol(NTP)isused.
Inthepreviousexamples(HTTP,WebSockets)we'veonlyusedTCPconnections,butNTPisbasedonUDP.Thereareacoupleofdifferences,butit'sreallyeasytouse,thankstothegreatlibrariesthatcomewiththeESP8266ArduinoCore.
ThemaindifferencebetweenTCPandUDPisthatTCPneedsaconnectiontosendmessages:Firstahandshakeissentbytheclient,theserverresponds,andaconnectionisestablished,andtheclientcansenditsmessages.Aftertheclienthasreceivedtheresponseoftheserver,theconnectionisclosed(exceptwhenusingWebSockets).Tosendanewmessage,theclienthastoopenanewconnectiontotheserverfirst.Thisintroduceslatencyandoverhead.
UDPdoesn'tuseaconnection,aclientcanjustsendamessagetotheserverdirectly,andtheservercanjustsendaresponsemessagebacktotheclientwhenithasfinishedprocessing.Thereis,however,noguaranteethatthemessageswillarriveattheirdestination,andthere'snowaytoknowwhethertheyarrivedornot(withoutsendinganacknowledgement,ofcourse).Thismeansthatwecan'thalttheprogramtowaitforaresponse,becausetherequestorresponsepacketcouldhavebeenlostontheInternet,andtheESP8266willenteraninfiniteloop.
Insteadofwaitingforaresponse,wejustsendmultiplerequests,withafixedintervalbetweentworequests,andjustregularlycheckifaresponsehasbeenreceived.
GettingthetimeLet'stakealookatanexamplethatusesUDPtorequestthetimefromaNTPserver.
Libraries,constantsandglobals
#include<ESP8266WiFi.h>#include<ESP8266WiFiMulti.h>#include<WiFiUdp.h>
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
WiFiUDPUDP;//CreateaninstanceoftheWiFiUDPclasstosendandreceive
IPAddresstimeServerIP;//time.nist.govNTPserveraddressconstchar*NTPServerName="time.nist.gov";
constintNTP_PACKET_SIZE=48;//NTPtimestampisinthefirst48bytesofthemessage
byteNTPBuffer[NTP_PACKET_SIZE];//buffertoholdincomingandoutgoingpackets
TouseUDP,wehavetoincludetheWiFiUdplibrary,andcreateaUDPobject.We'llalsoneedtoallocatememoryforabuffertostoretheUDPpackets.ForNTP,weneedabufferof48byteslong.ToknowwheretosendtheUDPpacketsto,weneedthehostnameoftheNTPserver,thisistime.nist.gov.
Setup
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println("\r\n");
startWiFi();//Trytoconnecttosomegivenaccesspoints.Thenwaitforaconnection
startUDP();
if(!WiFi.hostByName(NTPServerName,timeServerIP)){//GettheIPaddressoftheNTPserverSerial.println("DNSlookupfailed.Rebooting.");Serial.flush();ESP.reset();}Serial.print("TimeserverIP:\t");Serial.println(timeServerIP);Serial.println("\r\nSendingNTPrequest...");sendNTPpacket(timeServerIP);}
Inthesetup,wejuststartourSerialandWi-Fi,asusual,andwestartUDPaswell.We'lllookattheimplementationofthisfunctionlater.WeneedtheIPaddressoftheNTPserver,soweperformaDNSlookupwiththeserver'shostname.There'snotmuchwecandowithouttheIPaddressofthetimeserver,soifthelookupfails,reboottheESP.IfwedogetanIP,sendthefirstNTPrequest,andentertheloop.
Loop
unsignedlongintervalNTP=60000;//RequestNTPtimeeveryminuteunsignedlongprevNTP=0;unsignedlonglastNTPResponse=millis();uint32_ttimeUNIX=0;
unsignedlongprevActualTime=0;
voidloop(){unsignedlongcurrentMillis=millis();
if(currentMillis-prevNTP>intervalNTP){//IfaminutehaspassedsincelastNTPrequest
![Page 44: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/44.jpg)
prevNTP=currentMillis;Serial.println("\r\nSendingNTPrequest...");sendNTPpacket(timeServerIP);//SendanNTPrequest}
uint32_ttime=getTime();//CheckifanNTPresponsehasarrivedandgetthe(UNIX)timeif(time){//IfanewtimestamphasbeenreceivedtimeUNIX=time;Serial.print("NTPresponse:\t");Serial.println(timeUNIX);lastNTPResponse=currentMillis;}elseif((currentMillis-lastNTPResponse)>3600000){Serial.println("Morethan1hoursincelastNTPresponse.Rebooting.");Serial.flush();ESP.reset();}
uint32_tactualTime=timeUNIX+(currentMillis-lastNTPResponse)/1000;if(actualTime!=prevActualTime&&timeUNIX!=0){//IfasecondhaspassedsincelastprintprevActualTime=actualTime;Serial.printf("\rUTCtime:\t%d:%d:%d",getHours(actualTime),getMinutes(actualTime),getSeconds(actualTime));}}
ThefirstpartoftheloopsendsanewNTPrequesttothetimeservereveryminute.ThisisbasedonBlinkWithoutDelay.ThenwecallthegetTimefunctiontocheckifwe'vegotanewresponsefromtheserver.Ifthisisthecase,weupdatethetimeUNIXvariablewiththenewtimestampfromtheserver.Ifwedon'tgetanyresponsesforanhour,thenthere'ssomethingwrong,sowereboottheESP.Thelastpartprintstheactualtime.TheactualtimeisjustthelastNTPtimeplusthetimesincewereceivedthatNTPmessage.
Setupfunctions
Nothingspecialhere,justafunctiontoconnecttoWi-Fi,andanewfunctiontostartlisteningforUDPmessagesonport123.
voidstartWiFi(){//Trytoconnecttosomegivenaccesspoints.ThenwaitforaconnectionwifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting");while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnectdelay(250);Serial.print('.');}Serial.println("\r\n");Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.print(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputerSerial.println("\r\n");}
voidstartUDP(){Serial.println("StartingUDP");UDP.begin(123);//StartlisteningforUDPmessagesonport123Serial.print("Localport:\t");Serial.println(UDP.localPort());Serial.println();}
Helperfunctions
uint32_tgetTime(){if(UDP.parsePacket()==0){//Ifthere'snoresponse(yet)return0;}UDP.read(NTPBuffer,NTP_PACKET_SIZE);//readthepacketintothebuffer//Combinethe4timestampbytesintoone32-bitnumberuint32_tNTPTime=(NTPBuffer[40]<<24)|(NTPBuffer[41]<<16)|(NTPBuffer[42]<<8)|NTPBuffer[43];//ConvertNTPtimetoaUNIXtimestamp://UnixtimestartsonJan11970.That's2208988800secondsinNTPtime:constuint32_tseventyYears=2208988800UL;//subtractseventyyears:uint32_tUNIXTime=NTPTime-seventyYears;returnUNIXTime;}
voidsendNTPpacket(IPAddress&address){memset(NTPBuffer,0,NTP_PACKET_SIZE);//setallbytesinthebufferto0//InitializevaluesneededtoformNTPrequestNTPBuffer[0]=0b11100011;//LI,Version,Mode//sendapacketrequestingatimestamp:UDP.beginPacket(address,123);//NTPrequestsaretoport123UDP.write(NTPBuffer,NTP_PACKET_SIZE);UDP.endPacket();}
inlineintgetSeconds(uint32_tUNIXTime){returnUNIXTime%60;}
inlineintgetMinutes(uint32_tUNIXTime){returnUNIXTime/60%60;}
inlineintgetHours(uint32_tUNIXTime){returnUNIXTime/3600%24;}
InthegetTimefunction,wefirsttrytoparsetheUDPpacket.Ifthere'snopacketavailable,thefunctionjustreturns0.IfthereisaUDPpacketavailablehowever,readitintothebuffer.TheNTPtimestampis32bitsor4byteswide,sowecombinethesebytesintoonelongnumber.ThisnumberisthenumberofsecondssinceJan1,1900,00:00:00,butmostapplicationsuseUNIXtime,thenumberofsecondssinceJan1,1970,00:00:00(UNIXepoch).ToconvertfromNTPtimetoUNIXtime,wejustsubtract70yearsworthofseconds.
![Page 45: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/45.jpg)
TorequestthetimefromtheNTPserver,youhavetosendacertainsequenceof48bytes.Wedon'tneedanyfancyfeatures,sojustsetthefirstbytetorequestthetime,andleaveallother47byteszero.Toactuallysendthepacket,youhavetostartthepacket,specifyingtheIPaddressoftheserver,andtheNTPportnumber,port123.Thenjustwritethebuffertothepacket,andsenditwithendPacket.
Thelastthreefunctionsarejustsomesimplemathtoconvertsecondstohours,minutesandseconds.
Usingtheexample
EnteryourWi-Ficredentialsonlines79-81,andhitupload.IfyouhaveaworkingInternetconnection,youshouldgetanoutputthatlookslikethis:
Connecting.........
ConnectedtoWi-FiSSIDIPaddress: 192.168.1.2
StartingUDPLocalport: 123
TimeserverIP:216.229.0.179
SendingNTPrequest...NTPresponse: 1488378061UTCtime: 14:21:53SendingNTPrequest...NTPresponse: 1488378114UTCtime: 14:22:53SendingNTPrequest...NTPresponse: 1488378174UTCtime: 14:23:53SendingNTPrequest...NTPresponse: 1488378234UTCtime: 14:24:53SendingNTPrequest...NTPresponse: 1488378294UTCtime: 14:25:53...
Youshouldseethetimeupdateeverysecond,andSendingNTPrequest...shouldshowupeveryminute.Ifyoudon'thaveanInternetconnection,theDNSlookupofthetimeserverwillfail:
Connecting.........
ConnectedtoWi-FiSSIDIPaddress: 192.168.1.2
StartingUDPLocalport: 123
DNSlookupfailed.Rebooting.
etsJan82013,rstcause:2,bootmode:(3,6)
Ifyourconnectionisnotreliable,orifthere'sheavytraffic,youmightencountersomedroppedpackets:
SendingNTPrequest...NTPresponse: 1488378780UTCtime: 14:33:54SendingNTPrequest...UTCtime: 14:34:54SendingNTPrequest...NTPresponse: 1488378895UTCtime: 14:35:0
Asyoucansee,theESPneverreceivedaresponsetothesecondNTPrequest.That'snotreallyanissue,aslongasatleastsomepacketsmakeitthrough.
Localtimeanddaylightsavings
AnNTPserverreturnstheUTCtime.Ifyouwantlocaltime,youhavetocompensateforyourtimezoneanddaylightsavings.Forexample,ifyouwantCET(CentralEuropeanTime),youhavetoadd3600totheUNIXtimeduringwinter,(3600s=1h),and7200duringsummer(DST).
![Page 46: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/46.jpg)
DataloggingAcommonuseforIoTdevicesliketheESP8266ismonitoringsensors.Usingthecodeinthepreviousexample,wecanrequestthetime,andsavesomesensorvaluestoafile.Ifwerunaserveraswell,wecanshowthisdatainaprettygraphinawebpage.
TemperatureloggerInthefollowingexample,we'lluseaDS18S20temperaturesensortologthetemperatureovertimeandsaveittotheSPIFFS.Itcanthenbedisplayedinagraphinthebrowser.
Installinglibraries
First,downloadtheDallasTemperaturelibrarybyMilesBurtonandtheOneWirelibrarybyJimStudt:GotoSketch>IncludeLibrary...>ManageLibrariesandsearchfor'DallasTemperature'and'OneWire'(makesureyoudownloadthecorrectversion).
Hardware
ConnectthegroundoftheDS18S20temperaturesensor(pin1)tothegroundoftheESP,connectthedatapin(pin2)toGPIO5,andVCC(pin3)tothe3.3VoftheESP.Finally,connecta4k7ΩresistorbetweenthedatapinandVCC.
Libraries,constantsandglobals
#include<OneWire.h>#include<DallasTemperature.h>#include<ESP8266WiFi.h>#include<ESP8266WiFiMulti.h>#include<WiFiUdp.h>#include<ArduinoOTA.h>#include<ESP8266WebServer.h>#include<ESP8266mDNS.h>#include<FS.h>
#defineONE_HOUR3600000UL
#defineTEMP_SENSOR_PIN5
OneWireoneWire(TEMP_SENSOR_PIN);//SetupaOneWireinstancetocommunicatewithOneWiredevices
DallasTemperaturetempSensors(&oneWire);//Createaninstanceofthetemperaturesensorclass
ESP8266WebServerserver=ESP8266WebServer(80);//createawebserveronport80
FilefsUploadFile;//aFilevariabletotemporarilystorethereceivedfile
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
constchar*OTAName="ESP8266";//AnameandapasswordfortheOTAserviceconstchar*OTAPassword="esp8266";
constchar*mdnsName="esp8266";//DomainnameforthemDNSresponder
WiFiUDPUDP;//CreateaninstanceoftheWiFiUDPclasstosendandreceiveUDPmessages
IPAddresstimeServerIP;//Thetime.nist.govNTPserver'sIPaddressconstchar*ntpServerName="time.nist.gov";
constintNTP_PACKET_SIZE=48;//NTPtimestampisinthefirst48bytesofthemessage
bytepacketBuffer[NTP_PACKET_SIZE];//Abuffertoholdincomingandoutgoingpackets
TheonlynewthingsherearetheOneWireandDallasTemperaturelibraries,togetthetemperaturefromthesensor.
Setup
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println("\r\n");
tempSensors.setWaitForConversion(false);//Don'tblocktheprogramwhilethetemperaturesensorisreadingtempSensors.begin();//Startthetemperaturesensor
if(tempSensors.getDeviceCount()==0){Serial.printf("NoDS18x20temperaturesensorfoundonpin%d.Rebooting.\r\n",TEMP_SENSOR_PIN);Serial.flush();ESP.reset();}
startWiFi();//StartaWi-Fiaccesspoint,andtrytoconnecttosomegivenaccesspoints.ThenwaitforeitheranAPorSTAconnection
startOTA();//StarttheOTAservice
startSPIFFS();//StarttheSPIFFSandlistallcontents
startMDNS();//StartthemDNSresponder
startServer();//StartaHTTPserverwithafilereadhandlerandanuploadhandler
startUDP();//StartlisteningforUDPmessagestoport123
WiFi.hostByName(ntpServerName,timeServerIP);//GettheIPaddressoftheNTPserverSerial.print("TimeserverIP:\t");Serial.println(timeServerIP);
sendNTPpacket(timeServerIP);}
![Page 47: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/47.jpg)
Inthesetup,there'snotmuchneweither,wejuststartthetemperaturesensor,andcheckifwecancommunicatewithit.Ifnotemperaturesensorisfound,theESPresets.
Gettingthetemperaturefromthesensormaytakesometime(upto750ms).Wedon'twantourlooptotakelongerthanacoupleofmilliseconds,sowecan'twait750ms.Ifwedid,theHTTPserveretc.wouldstarttomisbehave.Thesolutionistorequestthetemperaturefirst.Thesensorwillthenstartreadingtheanalogtemperature,andstoresitinitsmemory.Inthemeantime,theloopjustkeepsonrunning,theserverrefreshesetc.After750ms,wecontactthesensoragain,andreadthetemperaturefromitsmemory.Totellthelibrarythatwedon'twanttowaitfortheanalogtodigitalconversionofthesensor,weusesetWaitForConversion.
Loop
constunsignedlongintervalNTP=ONE_HOUR;//UpdatethetimeeveryhourunsignedlongprevNTP=0;unsignedlonglastNTPResponse=millis();
constunsignedlongintervalTemp=60000;//DoatemperaturemeasurementeveryminuteunsignedlongprevTemp=0;booltmpRequested=false;constunsignedlongDS_delay=750;//ReadingthetemperaturefromtheDS18x20cantakeupto750ms
uint32_ttimeUNIX=0;//Themostrecenttimestampreceivedfromthetimeserver
voidloop(){unsignedlongcurrentMillis=millis();
if(currentMillis-prevNTP>intervalNTP){//RequestthetimefromthetimeservereveryhourprevNTP=currentMillis;sendNTPpacket(timeServerIP);}
uint32_ttime=getTime();//Checkifthetimeserverhasresponded,ifso,gettheUNIXtimeif(time){timeUNIX=time;Serial.print("NTPresponse:\t");Serial.println(timeUNIX);lastNTPResponse=millis();}elseif((millis()-lastNTPResponse)>24UL*ONE_HOUR){Serial.println("Morethan24hourssincelastNTPresponse.Rebooting.");Serial.flush();ESP.reset();}
if(timeUNIX!=0){if(currentMillis-prevTemp>intervalTemp){//Everyminute,requestthetemperaturetempSensors.requestTemperatures();//Requestthetemperaturefromthesensor(ittakessometimetoreadit)tmpRequested=true;prevTemp=currentMillis;Serial.println("Temperaturerequested");}if(currentMillis-prevTemp>DS_delay&&tmpRequested){//750msafterrequestingthetemperatureuint32_tactualTime=timeUNIX+(currentMillis-lastNTPResponse)/1000;//TheactualtimeisthelastNTPtimeplusthetimethathaselapsedsincethelastNTPresponsetmpRequested=false;floattemp=tempSensors.getTempCByIndex(0);//Getthetemperaturefromthesensortemp=round(temp*100.0)/100.0;//roundtemperatureto2digits
Serial.printf("Appendingtemperaturetofile:%lu,",actualTime);Serial.println(temp);FiletempLog=SPIFFS.open("/temp.csv","a");//WritethetimeandthetemperaturetothecsvfiletempLog.print(actualTime);tempLog.print(',');tempLog.println(temp);tempLog.close();}}else{//Ifwedidn'treceiveanNTPresponseyet,sendanotherrequestsendNTPpacket(timeServerIP);delay(500);}
server.handleClient();//runtheserverArduinoOTA.handle();//listenforOTAevents}
Thelooplooksalotmorecomplex,butit'sactuallyprettysimple.It'sallbasedonBlinkWithoutDelay.There'stwothingsgoingon:
1. Everyhour,theESPrequeststhetimefromanNTPserver.Thenitconstantlychecksforaresponse,andupdatesthetimeifitgetsanNTPresponse.Ifithasn'treceivedanyresponsesforover24hours,there'ssomethingwrong,andtheESPresetsitself.
2. Everyminute,theESPrequeststhetemperaturefromtheDS18x20sensor,andsetsthe'tmpRequested'flag.Thesensorwillstarttheanalogtodigitalconversion.750msaftertherequest,whentheconversionshouldbefinished,theESPreadsthetemperaturefromthesensor,andresetstheflag(otherwise,itwouldkeeponreadingthesametemperatureoverandoveragain).ThenitwritesthetimeandthetemperaturetoafileinSPIFFS.BysavingitasaCSVfileinthefilesystem,wecaneasilydownloadittotheclient(usingthewebserverthatisrunning),andit'seasytoparsewithJavaScript.
IfwemissthefirstNTPresponse,timeUNIXwillbezero.Ifthat'sthecase,wesendanotherNTPrequest(otherwise,thenextrequestwouldbeanhourlater,andthetemperatureloggingonlystartswhenthetimeisknown).
WealsoneedtoruntheserverandOTAfunctionstohandleHTTPandOTArequests.
Setupfunctions,serverhandlersandhelperfunctions
Thesefunctionshaven'tchangesincethepreviousexample,sothere'snoneedtocoverthemhere.Youdoneedthemtogettheprogramrunning,though.DownloadtheZIParchivewithexamplesforthefullsketch.
HTMLandJavaScript
There'ssomeHTMLandJavaScriptfilestoplotthetemperatureusingGoogleGraphs.Iwon'tcoverithere,butifyouwan'ttoknow
![Page 48: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/48.jpg)
howitworks,youcanfindthefilesintheZIParchive.
Usingtheexample
SettheSPIFFSsizeto64KBorlargerifyouplantouseitforprolongedperiodsoftime.(Youcouldalsoincreasetheloggingintervalonline80tosavespace.)EnteryourWi-Ficredentialsonlines138-140,andhitupload.ThenuploadthewebpagesandscriptstoSPIFFSusingTools>ESP8266SketchDataUpload.Makesureyouhavethetemperaturesensorconnected,asdescribedatthetopofthispage.Openaterminaltoseeifitworks.Youshouldseesomethinglikethis:
Connecting..........
ConnectedtoSSIDIPaddress: 192.168.1.2
OTAready
SPIFFSstarted.Contents: FSFile:/favicon-144x144.png,size:2.81KB FSFile:/temperatureGraph.js.gz,size:1.17KB FSFile:/temp.csv,size:42.50KB FSFile:/success.html.gz,size:456B FSFile:/edit.html.gz,size:700B FSFile:/main.css.gz,size:349B FSFile:/index.html.gz,size:795B FSFile:/manifest.json,size:169B FSFile:/favicon.ico.gz,size:1.91KB
mDNSresponderstarted:http://esp8266.localHTTPserverstarted.StartingUDPLocalport: 123TimeserverIP:216.229.0.179SendingNTPrequestNTPresponse: 1488666586TemperaturerequestedAppendingtemperaturetofile:1488666627,20.00TemperaturerequestedAppendingtemperaturetofile:1488666687,19.94Temperaturerequested...
Letitrunforacoupleofminutes,togathersometemperaturedata.Thenopenawebbrowser,andgotohttp://esp8266.local/.Youshouldgetagraphshowingthetemperaturecurve.Youcanusethearrowbuttonstotravelthroughtime,andthe+and-buttonstozoominorout.Theresetbuttonresetsthezoom,andjumpsbacktothepresent.Refreshrequeststhelatesttemperaturedata.
Ifyouwant,youcanstillgotohttp://esp8266.local/edit.htmltouploadnewfiles.
Thewebinterfaceshouldlooklikethis:
ItworksonWindows,LinuxandAndroid,butiOSseemstohavesomeproblemsrenderingthegraph(inbothChromeandSafari).
![Page 49: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/49.jpg)
EmailnotifierAnothergreatuseforIoTdevicesisdisplayingthingsliketrafficinformation,weatherforecast,socialmediaupdates...ThisrequiresustosendanHTTPGETrequesttotheserveroftheservicewe'dliketoaccess.MostpopularserviceshaveAPI(ApplicationProgrammingInterface)documentsthatexplainthatexplainhowyoucanretrievecertaininformation,andwhatformatthatinformationisin.Inthefollowingexample,we'lllookatGmailspecifically,butthecodeshouldbesimilarforotherservices.
ShowingthenumberofunreademailsTocommunicatewithGoogle'sGmailservers,wehavetoestablishasecureconnectiontotheserverandsendasecureHTTPSrequestwithouremailaddressandpassword.GmailwillthenrespondwithanXMLdocumentcontainingallkindsofinformation,like(partsof)yourmostrecentmessagesandthenumberofunreademails.
Tomakesurewedon'tsendourGooglepasswordtoamaliciousserver,wehavetochecktheserver'sidentity,usingtheSHA-1fingerprintoftheSSLcertificate.Thisisauniquesequenceofhexadecimalcharactersthatidentifiestheserver.
Allowingaccesstotheemailfeed
Theonlyway(Iknowof)togetemailinformationfromGoogleontheESPcurrentlyistheGoogleAtomFeed.Thisisanoldermethod,soyouhavetochangeyourGmailsettingstoallowaccesstothefeed.Gotohttps://www.google.com/settings/security/lesssecureappstoenableaccessfor"lesssecureapps":
![Page 50: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/50.jpg)
![Page 51: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/51.jpg)
Untilthere'ssupportforthenewOAuth2protocolontheESP,we'llhavetousetheold,lesssecuremethod.
Hardware
ConnectanLED(+resistor)topin13,asanunreademailindicator.
TheCode
#include<WiFiClientSecure.h>//IncludetheHTTPSlibrary#include<ESP8266WiFi.h>//IncludetheWi-Filibrary#include<ESP8266WiFiMulti.h>//IncludetheWi-Fi-Multilibrary
ESP8266WiFiMultiwifiMulti;//CreateaninstanceoftheESP8266WiFiMulticlass,called'wifiMulti'
constchar*host="mail.google.com";//theGmailserverconstchar*url="/mail/feed/atom";//theGmailfeedurlconstinthttpsPort=443;//theporttoconnecttotheemailserver
//TheSHA-1fingerprintoftheSSLcertificatefortheGmailserver(seebelow)constchar*fingerprint="D390FC8207E60DC2CEF99D797FECF6E63ECB8BB3";
//TheBase64encodedversionofyourGmaillogincredentials(seebelow)constchar*credentials="ZW1haWwuYWRkcmVzc0BnbWFpbC5jb206cGFzc3dvcmQ=";
constbyteled=13;
voidsetup(){Serial.begin(115200);//StarttheSerialcommunicationtosendmessagestothecomputerdelay(10);Serial.println('\n');
pinMode(led,OUTPUT);
wifiMulti.addAP("ssid_from_AP_1","your_password_for_AP_1");//addWi-FinetworksyouwanttoconnecttowifiMulti.addAP("ssid_from_AP_2","your_password_for_AP_2");wifiMulti.addAP("ssid_from_AP_3","your_password_for_AP_3");
Serial.println("Connecting...");inti=0;while(wifiMulti.run()!=WL_CONNECTED){//WaitfortheWi-Fitoconnect:scanforWi-Finetworks,andconnecttothestrongestofthenetworksabovedelay(250);Serial.print('.');}Serial.println('\n');Serial.print("Connectedto");Serial.println(WiFi.SSID());//Telluswhatnetworkwe'reconnectedtoSerial.print("IPaddress:\t");Serial.println(WiFi.localIP());//SendtheIPaddressoftheESP8266tothecomputerSerial.println('\n');}
voidloop(){intunread=getUnread();if(unread==0){Serial.println("\r\nYou'vegotnounreademails");digitalWrite(led,LOW);}elseif(unread>0){Serial.printf("\r\nYou'vegot%dnewmessages\r\n",unread);digitalWrite(led,HIGH);}else{Serial.println("Couldnotgetunreadmails");}Serial.println('\n');delay(5000);}
intgetUnread(){//afunctiontogetthenumberofunreademailsinyourGmailinboxWiFiClientSecureclient;//UseWiFiClientSecureclasstocreateTLS(HTTPS)connectionSerial.printf("Connectingto%s:%d...\r\n",host,httpsPort);if(!client.connect(host,httpsPort)){//ConnecttotheGmailserver,onport443Serial.println("Connectionfailed");//Iftheconnectionfails,stopandreturnreturn-1;}
if(client.verify(fingerprint,host)){//ChecktheSHA-1fingerprintoftheSSLcertificateSerial.println("Certificatematches");
![Page 52: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/52.jpg)
}else{//ifitdoesn'tmatch,it'snotsafetocontinueSerial.println("Certificatedoesn'tmatch");return-1;}
Serial.print("RequestingURL:");Serial.println(url);
client.print(String("GET")+url+"HTTP/1.1\r\n"+"Host:"+host+"\r\n"+"Authorization:Basic"+credentials+"\r\n"+"User-Agent:ESP8266\r\n"+"Connection:close\r\n\r\n");//SendtheHTTPrequestheaders
Serial.println("Requestsent");
intunread=-1;
while(client.connected()){//Waitfortheresponse.TheresponseisinXMLformatclient.readStringUntil('<');//readuntilthefirstXMLtagStringtagname=client.readStringUntil('>');//readuntiltheendofthistagtogetthetagnameif(tagname=="fullcount"){//ifthetagis<fullcount>,thenextstringwillbethenumberofunreademailsStringunreadStr=client.readStringUntil('<');//readuntiltheclosingtag(</fullcount>)unread=unreadStr.toInt();//convertfromStringtointbreak;//stopreading}//ifthetagisnot<fullcount>,repeatandreadthenexttag}Serial.println("Connectionclosed");
returnunread;//Returnthenumberofunreademails}
Howitworks
Thesetupshouldbeprettyfamiliarbynow.TheonlynewthingisthegetUnread()function:First,itstartsanHTTPSconnectiontotheGmailserveronport443.Thenitchecksifthefingerprintofthecertificatematches,soitknowsthatit'stherealGoogleserver,andnotsomehacker.Ifthecertificatedoesn'tmatch,it'snotsafetosendthecredentialstotheserver.
Ifitmatches,wesendaHTTPGETrequesttotheserver:
GET/mail/feed/atomHTTP/1.1\r\nHost:mail.google.com\r\nAuthorization:BasicaVeryLongStringOfBase64EncodedCharacters=\r\nUser-Agent:ESP8266\r\nConnection:close\r\n\r\n
TherequestcontainstheURIwewanttoaccess(inthiscasethisistheAtomfeedURL),thehost(whichismail.google.com),andthebase64-encodedversionofyourlogincredentials.Asyoucansee,thedifferentlinesoftheheaderareseparatedbyaCRLF(CarriageReturn+LineFeed,\r\n).TwoCRLF'smarktheendoftheheader.TheGmailserverwillprocessourrequest,andsendthefeedasaresponseoverthesameHTTPSconnection.ThisresponseisanXMLdocument,thatconsistsoftagswithangledbrackets,justlikeHTML.Ifyouneedalotofdata,it'srecommendedtouseaproperXMLparserlibrary,butweonlyneedonetag,sowecanjustskimthroughtheresponsetextuntilwefindthe<fullcount>x</fullcount>tag.Thenumberinsidethistagisthenumberofunreademailsintheinbox.Wecanjustconvertittoaninteger,andstopreading.
ThisistheformatoftheXMLfeed,youcanseethefullcounttagonline5:
<?xmlversion="1.0"encoding="UTF-8"?><feedxmlns="http://purl.org/atom/ns#"version="0.3"><title>[email protected]</title><tagline>NewmessagesinyourGmailInbox</tagline><fullcount>5</fullcount><linkrel="alternate"href="https://mail.google.com/mail"type="text/html"/><modified>2017-03-05T15:54:06Z</modified><entry><title>Newsign-infromFirefoxonLinux</title><summary>Newsign-infromFirefoxonLinuxHiESP8266,YourGoogleAccountesp8266.test.mail@gmail.comwasjustusedtosigninfromFirefoxonLinux.ESP8266Testesp8266.test.mail@gmail.comLinuxSunday,</summary><linkrel="alternate"href="https://mail.google.com/[email protected]&message_id=123456789&view=conv&extsrc=atom"type="text/html"/><modified>2017-03-05T15:52:45Z</modified><issued>2017-03-05T15:52:45Z</issued><id>tag:gmail.google.com,2004:123456789123456789</id><author><name>Google</name><email>[email protected]</email></author></entry>
...
</feed>
Theloopjustprintsthenumberofunreademails,andturnsonanLEDifyouhaveunreadmessages.
GettingthefingerprintoftheGmailserver
LikeImentionedbefore,weneedafingerprinttochecktheidentityoftheserver.Togetthisfingerprint,executethefollowingcommandinaterminal(Linux&Mac):
openssls_client-connectmail.google.com:443</dev/null2>/dev/null|opensslx509-fingerprint-noout-in/dev/stdin|sed's/://g'
Copythehexadecimalfingerprintstringandpasteitintothesketchonline12.Forexample:
constchar*fingerprint="D390FC8207E60DC2CEF99D797FECF6E63ECB8BB3";
![Page 53: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/53.jpg)
Encodingyourlogincredentials
Togetaccesstothefeed,youhavetoenteryouremailaddressandpassword.Youcan'tsendthemasplaintext,youhavetoencodethemtobase64first.Usethefollowingcommandinaterminal(Linux&Mac):
echo-n"[email protected]:password"|base64
Thenaddittoline15ofthesketch.Forexample:
constchar*credentials="ZW1haWwuYWRkcmVzc0BnbWFpbC5jb206cGFzc3dvcmQ=";
OtherAPIs
ManyservicessendtheirdatainJSONformat.Ifyoujustneedonepieceofinformation,youmaybeabletousethesameapproachofscanningtheentireJSONtextforacertainword,butit'smucheasiertouseaJSONparser,liketheArduinoJsonlibrary.ItwilldeserializetheJSONtext,andcreateaJSONobject,youcouldcompareittoanassociativearray.Youcanbrowsetheentiretreestructure,andeasilyfindthedatayou'relookingfor.Thedownsideisthatitusesmorememory.
![Page 54: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/54.jpg)
AdvancedDNSCaptivePortal
WhenusingtheESP8266inaccesspointmode,youprobablywanttoredirectuserstotherightpage.Youcandothisbycreatingacaptiveportal,usingDNS.It'sbasicallyjustaDNSserverthatwillconvertallhostnamestotheESP'sownIPaddress.ThistechniqueisalsousedbyopenWi-Finetworksthatredirectyoutoaloginpagebeforeyoucanstartbrowsingtheinternet.
Wi-Ficonfiguration
IfyouwanttobeabletochangetheWi-Ficonnectionsettingswithoutre-uploadingthecode,youcouldtakealookattheWiFiManagerlibrarybytzapu.Thiswilltrytoconnecttoknownnetworks,butifitfails,itwillstartaWi-Fiaccesspoint.Youcanthenconnecttothisaccesspoint,openthebrowser,andpickanetworktoconnectto.Thenewconfigurationissaved.TheWiFiManagerlibraryusesacaptiveportaltopresentyouwiththerightWi-Fisettingspage.YoucouldalsoimplementaWi-Fimanageryourself,oryoucanjustcheckouttheexamplethatcomeswiththeESP8266ArduinoCore(Examples>DNSServer>CaptivePortalAdvanced).
I²STheESP8266hasanI²SbusontheRXDpin.Itcanrunat80MHz,andhasDMA(directmemoryaccess),soit'sreallyfast.ItsmainpurposeistoconnectanI²SDAC(DigitaltoAnalogConverter)tohaveanaudiooutput,butyoucanuseitforotherthingsaswell.Forexample,CNLohrmanagedtotransmitanalogtelevision,byconnectinganantennawiretotheI²Spin.YoucanalsouseittocontrolWS2812BsLEDs.YoucanevenuseittocommunicateoverEthernet(notreallyuseful,anddefinitelynotrecommended,butitworks).AnothergreatusefortheI²Sbusisoutputtingdatatoshiftregisters.Thisgivesyouextraoutputsthatarereasonablyfast,forthingslikeLEDsorsteppermotors.
Otherexamples
YoucanfindlotsofotherexamplesintheArduinoIDE,I'drecommendtocheckthoseoutaswell.
YouTubeThere'ssomegreatchannelsonYouTubethatdoamazingthingswiththeESP8266.Here'sashortlistoftheonesI'mcurrentlyfollowing.Ifyou'vegotmorerecommendation,justleaveacomment!
AndreasSpiessCNLohrAcroboticMiikaKurkela
![Page 55: Pieter P, 08-03-2017 A Beginner's Guide to the ESP8266 · A Beginner's Guide to the ESP8266 Pieter P, 08-03-2017 Some time ago, I wrote a Beginner's Guide to Arduino that seems to](https://reader030.fdocuments.in/reader030/viewer/2022040207/5e144f88b5b1b51d715ab8cb/html5/thumbnails/55.jpg)
Inconclusion...Congratulations,you'vereachedtheendofthisratherlongarticleonthebasicsoftheESP8266.Ihopethiswasinterestingtoyou,andthatyou'llusethisknowledgeforyourownDIYprojects.
Ifyouhaveanyremarksorifyouwanttohelpimprovethisguide,don'thesitatetoleaveacommentortosendmeamessage.
Thankyouforreading!Pieter,8-3-2017