CMM2: V5.07.00b11: json support with full ESP-01 example code


Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 6619
Posted: 03:51pm 31 Jan 2021      

Here is a simple webserver using the ESP-01 in tcp server mode. Just substitute the login for your network in lines 8 and 9





Option explicit
option default integer
const MaxLen=4096
const max=20

' Global variables
const quote=chr$(34)
CONST SSID$=quote+"mySSID"+quote
CONST SSIDPassword$=quote+"myPASSWORD"+quote
'
const crlf$=chr$(13)+chr$(10)
const header$="<!DOCTYPE html>"
const starttext$="HTTP"
const pnf$="<html><body>Page not Found</body></html>"
const title$="<html><meta charset="+quote+"UTF-8"+quote+"><head><title>Remote Thermostat</title></head><body>"
const ending$="</form></body></html>"
const form$="<form name='f1' method='get' action='D'>"
const h2$="<h2 align='left'>Remote Thermostat V3.0</h2>"
const code$="Update Code: <input type='text' name='S' size='6' value='000000'><br>"
const tstart$="<p><TABLE BORDER='1' CELLSPACING='0' CELLPADDING='5'>"
const heat$="<TR><TD>Heating</TD>"
const hon$="<TD BGCOLOR='#ff0000'> On</TD></TR>"
const hoff$="<TD BGCOLOR='#00ff00'>Off</TD></TR>"
const tend$="</TABLE></p>"
const h3$="<TR><TD></TD><TD>Temperature</TD></TR>"
const s1$="<TR><TD>Current</TD><TD>"
const s2$="<TR><TD>Max</TD><TD>"
const s3$="<TR><TD>Min</TD><TD>"
const check$="<input name='C' type='checkbox' value='R' onClick='this.form.submit()'> Reset Max/Min"
const s4$="<TR><TD>Thermostat</TD>"
const s5$="<TD><input name='R' type='radio' checked='checked' value='"
const s6$="<TD><input name='R' type='radio' value='"
const click$=" 'onClick='this.form.submit()'> "
const degree$="C<br></TD>"
const offstr$="Off<br></TD>"
const onstr$="On<br></TD>"
const ON=1
const off=0
'
' Set up parameters
'
const starttemp=20 'set the lowest temperature on the thermostat select radio buttons
const hysteresis=2 ' 2 tenths of a degree either side of the setpoint
const waittime=1000 'wait time in readrequest before timeout
const password$="123456" 'password to access change mode


'
const dspin=42
const relaypin=5
'
Dim arg$(2,max) length 20
DIM integer inbuf(Maxlen\8) 'global input buffer

dim integer IPDno 'global IPD numbers used to ensure transmit is on correct IPD
dim integer heater,currenttemp,maxtemp,mintemp,setpoint
dim integer nparams
dim mypage$ 'variables used by main loop only
DIM integer obuff(2048\8) 'used to buffer writes to the internet to optimise speed

Init:
 tempr start dspin,3 'measure temp to 0.0625 degree accuracy
 mintemp=1000 'set to silly value to force reset if not saved
 maxtemp=-1000
 currenttemp=cint(tempr(dspin)*10)
 tempr start dspin,3
 var restore 'recover the setpoint and min and max temps if already saved
 maxmin 'update the maximum and minimum and save them if changed
 heater=off
 pin(relaypin)=heater
 setpin relaypin,dout
 setpoint=asc("E")
 pause 2000 'wait for ESP8266 to wake up afer power on
 open "com2:115200,4096" as #1
 close #1 'clear the buffer
 open "com2:115200,4096" as #1
 IF NOT Command(0, "AT",obuff(), 500) THEN END
 IF NOT Command(0, "AT+RST",obuff(), 10000,"WIFI GOT IP") THEN 'reset and check for valid connection
   PRINT "Set up WIFI on SSID: ",SSID$
   IF NOT Command(0, "AT+CWMODE_DEF=1",obuff(), 5000) THEN END 'set device mode (1=client, 2=AP, 3=both)
   IF NOT Command(0, "AT+CWLAP",obuff(), 30000) THEN END 'scan for WiFi hotspots
   longstring print inbuf() 'output the list of valid networks
   IF NOT Command(0, "AT+CWJAP_DEF="+SSID$+","+SSIDPassword$,obuff(), 20000,"WIFI GOT IP") THEN END 'connect
   IF NOT Command(0, "AT+CIFSR",obuff(), 5000) THEN END 'check IP address
 ENDIF

 IF NOT Command(0, "AT+CIPMUX=1",obuff(), 5000) THEN END
 IF NOT Command(0, "AT+CIPSERVER=1,80",obuff(), 5000) THEN END
 Print "Connected"

main:
DO
 currenttemp=cint(tempr(dspin)*10)
 updateheater
 tempr start dspin,3
 maxmin 'update the maximum and minimum and save them if changed
 if ReadRequest(waittime) then 'process HTML request
   mypage$=ucase$(parsehtmldata$(nparams)) 'parse the html request and get the page requested
   if mypage$<>"" then 'real request so do something
     if mypage$= "INDEX" then
       drawpage
     elseif mypage$="D" then
       if nparams<>0 then 'we have parameters to process
         if arg$(0,0)="S" and arg$(1,0) = password$ then
           if arg$(0,1)="C" and arg$(1,1)="R" then 'reset the max min to current
             maxtemp=currenttemp
             mintemp=currenttemp
             var save setpoint,maxtemp,mintemp
           endif
           if arg$(0,1)="R" then 'change the setpoint and update the heater if applicable
             setpoint=asc(arg$(1,1))
             var save setpoint,maxtemp,mintemp
             updateheater
           endif
         endif
       endif
       drawpage
     else
       SendText pnf$+crlf$+crlf$'invalid page
     endif
     EndSend 'clear the write buffer and terminate the write
   endif
 endif
LOOP
end
'
Function parsehtmldata$(paramcount as integer)
 local a$,b$
 local integer buf(Maxlen\8)
 local integer inpos,startparam,processargs
 paramcount=0
 inpos=lInstr(inbuf(),"GET /",1)
 if inpos=0 then
   parsehtmldata$=""
 else
   longstring mid buf(),inbuf(),inpos+5,1000
   inpos=lInstr(buf(),starttext$,1)
   If inpos>2 Then 'page request found
     inpos=inpos-2
     a$=lGetStr$(buf(),1,inPos)
     inpos=Instr(a$,"?")
     If inpos<>0 Then 'parameters found
       processargs=1
       parsehtmldata$=Left$(a$,inpos-1)
       a$=Mid$(a$,inpos+1)
       Do
         arg$(0,paramcount)=""
         arg$(1,paramcount)=""
         inpos=Instr(a$,"=")
         startparam=1
         arg$(0,paramcount)=Mid$(a$,startparam,inpos-startparam)
         startparam=inpos+1
         inpos=Instr(a$,"&")
         If inpos<>0 Then
           arg$(1,paramcount)=Mid$(a$,startparam,inpos-startparam)
           a$=Mid$(a$,inpos+1)
           paramcount=paramcount+1
         Else
           arg$(1,paramcount)=Mid$(a$,startparam)
           paramcount=paramcount+1
           processargs=0
         EndIf
       Loop while processargs
     Else
       parsehtmldata$=a$
     EndIf
   Else ' no page requested
     parsehtmldata$="INDEX"
   EndIf
 endif
End Function

sub maxmin
 local integer update=off
 if currenttemp>maxtemp then
   maxtemp=currenttemp
   update=on
 endif
 if currenttemp<mintemp then
   mintemp=currenttemp
   update=on
 endif
 if update then var save setpoint,maxtemp,mintemp
end sub

sub updateheater
 local integer hcalc
 if setpoint=asc("L") then
   pin(relaypin)=ON
   heater=on
 endif
 if setpoint=asc("A") then
   pin(relaypin)=OFF
   heater=oFF
 endif
 if setpoint>=asc("B") and setpoint<=asc("K") then
   hcalc=(setpoint-asc("B")+starttemp)*10 'setpoint temperature * 10
   hcalc = hcalc + hysteresis
   if currenttemp>=hcalc then 'turn heating off
     pin(relaypin)=OFF
     heater=oFF
   endif
   hcalc = hcalc - hysteresis - hysteresis
   if currenttemp<=hcalc then 'turn heating on
     pin(relaypin)=ON
     heater=oN
   endif
 endif
end sub

sub drawpage
 local integer loopcounter,tempconvert
 local b$
 sendText header$
 sendText title$+form$+h2$+code$
 sendText tstart$+heat$
 if heater then
   sendText hon$+tend$
 else
   sendText hoff$+tend$
 endif
 sendText tstart$
 sendText h3$
 b$=s1$+outtemp$(currenttemp)+degree$
 b$=b$+s2$+outtemp$(maxtemp)+degree$
 b$=b$+s3$+outtemp$(mintemp)+degree$
 sendText b$
 sendText tend$
 sendText check$
 sendText tstart$
 sendText s4$
 for loopcounter=asc("A") to asc("L")
   if loopcounter=setpoint then
     sendText s5$+chr$(loopcounter)
   else
     sendText s6$+chr$(loopcounter)
   endif
   sendText click$
   tempconvert=loopcounter-asc("B")+starttemp
   if loopcounter>asc("A") and loopcounter<asc("L") then sendText str$(tempconvert,2)+degree$
   if loopcounter=asc("A") then sendText offstr$
   if loopcounter=asc("L") then sendText onstr$
 next loopcounter
 sendText tend$
 sendText ending$+crlf$+crlf$
end sub
'
function outtemp$(t as integer)
 local integer tenths=t mod 10
 local integer units= t\10
 outtemp$=str$(units,3)+"."+chr$(tenths+48)
end function
'
sub EndSend
 local b$
 pause 25
 b$="AT+CIPSEND="+CHR$(IPDno+48)+","+STR$(llen(obuff())) 'send anything still in the buffer
 IF NOT Command(0,b$,obuff(), 500,">") THEN
   if lInstr(inbuf(),"link is not valid") then exit sub
 endif
 IF NOT Command(1, b$, obuff(),500) THEN END
 pause 25
 IF NOT Command(0, "AT+CIPCLOSE="+CHR$(IPDno+48),obuff(), 500) THEN
   if lInstr(inbuf(),"UNLINK") then
     longstring clear obuff()
     exit sub
   else
     end
   endif
 endif
 longstring clear obuff()
end sub

sub SendText(a$)
 local b$
 if len(a$)+llen(obuff())< 2048 then 'add the new string to the output buffer
   longstring append obuff(),a$
 else 'too big to fit so send the current output buffer
  pause 25
  b$="AT+CIPSEND="+CHR$(IPDno+48)+","+STR$(llen(obuff()))
   IF NOT Command(0,b$,obuff(),1000,">") THEN
     if lInstr(inbuf(),"link is not valid") then exit sub
   endif
   IF NOT Command(1, b$, obuff(),1000) THEN END
   longstring clear obuff()
longstring append obuff(),a$
 endif
end sub
'
FUNCTION ReadRequest(timeout%) as integer
 ReadRequest=0
 longstring Clear inbuf()
 timer=0
 do while TIMER<timeout% and LOC(#1)=0
 loop
 if TIMER>=timeout% then exit function
 do while loc(#1)<>0
   longstring append inbuf(),input$(min(255,loc(#1)),#1)
 loop
 if (NOT lInstr(inbuf(),"favicon",0)) and (NOT lInstr(inbuf(),"CONNECT FAIL",1)) then ReadRequest=1 'junk the favicon requests and disconnects
 IF lInstr(inbuf(),"IPD,0",1) then IPDno=0
 IF lInstr(inbuf(),"IPD,1",1) then IPDno=1
end function
'

end sub
'
FUNCTION Command(mode, AT$, outdata%(), timeout%, other$) as integer 'send a command and wait for the answer
 local i%=0,j%,ex%=0
 Local a$
 Command=0
 longstring Clear inbuf()
 if mode=0 then
   print #1,AT$+crlf$;
 else
   longstring print #1,obuff();
 endif
 TIMER=0
 i%=0
 do
   if TIMER>timeout% then
     ex%=0
     EXIT DO
   endif
   j%=LOC(#1)
   if j%>0 then
     i%=i%+min(255,j%)
     longstring append inbuf(),input$(min(255,j%),#1)
     if llen(inbuf())>4 and other$="" then
       if lInstr(inbuf(),"OK",1) then
         ex%=1
         exit DO
       endif
     endif
     if llen(inbuf())>7 then
       if lInstr(inbuf(),"ERROR",1) then
         ex%=2
         exit DO
       endif
     endif
     if llen(inbuf())>len(other$)+2 then
       if lInstr(inbuf(),other$,1) then
         ex%=3
         exit DO
       endif
     endif
   endif
 loop
 select case ex%
   case 0
     Print "Timeout : "+AT$
   case 1
     Command=1
   case 2
     Print "ERROR : "+AT$
   case 3
     Command=1
 end select
end function