![]() |
Forum Index : Microcontroller and PC projects : Armmite F4 Weather Station with ESP-01
Author | Message | ||||
lizby Guru ![]() Joined: 17/05/2016 Location: United StatesPosts: 3314 |
Inspired by lew247's rich pi-cromite weather station display (bottom of page 24) and Peter Mather's compass rose and ESP-01 wifi efforts, I decided to make a version for the Armmite F4. I signed up for an openweathermap.org account, downloaded the list of Cities, found the code for adjacent town of Liverpool, Nova Scotia, and after some fiddling on the PC was able to download the default data: {"coord":{"lon":-64.7155,"lat":44.0335},"weather":[{"id":802, "main":"Clouds","description":"scattered clouds","icon":"03d"}], "base":"stations","main":{"temp":278.94,"feels_like":269.44, "temp_min":278.71,"temp_max":279.15,"pressure":1008,"humidity":56}, "visibility":10000,"wind":{"speed":10.29,"deg":240,"gust":14.92}, "clouds":{"all":46},"dt":1612635812,"sys":{"type":1,"id":549, "country":"CA","sunrise":1612611013,"sunset":1612647345}, "timezone":-14400,"id":6057856,"name":"Liverpool","cod":200} From that I was able to work out how to extract the data. JSON$ is not available on the F4, so I wrote a very limited pseudo-json$ to pick out single values for single occurrences of a given key/name. I hung a DS18B20 off of pin 1 for "inside temperature", and wanted to get the outside temperature from another device I have on my network. I figured out how the ESP-01 TCP GET was working for openweathermap, and set up my device to write the temperature within {} to a web server with a command like this on the openWrt device: echo '{-3}' > /www/oat.html (If I had more than one value to provide from external sensors on my network, I'd put them out in pseudo-json$ format, e.g.: echo '{"oat":-3,"barnroom":18}' > /www/oat.html ) I read the DS18B20 with every program loop (there are no pauses except for processing for the ESP-01). If the temperature is dithering between one degree and another the display may change quite rapidly. I check the outside temperature once a minute. openweathermap.org says they won't allow you to retrieve your data more than once every 10 minutes, so I pick it up when minutes in time$ is at "00", "15", "30", "45". The seconds in the time display on the second line is updated every second except when the ESP-01 is working. I pre-configured the ESP-01 to connect to my network on powerup (in AT mode, with the AT version 1.7 recently linked by matherp), so MMBasic code to do that is not included. The standard 320x240 LCD is crisp, if small. Unfortunately, I can't get a good picture of it--tried both phone and camera. ![]() Dim integer lblue=RGB(172,209,255),grey=rgb(192,192,192),i,j,k,l,m,n Dim integer EspFlag=1,iconFlag=1,firstPassFlag=1,txtFont=1,ESPOKFlag% Dim integer ls%(1000),nNames=10,degrees, x_endpoint, y_endpoint Dim integer outsideTemp=-2, insideTemp=21, OldOutsideTemp, OldInsideTemp 'Dim cx% = 225, cy% = 100, wid% = 50 Dim cx% = mm.hres*.75-5, cy% = (mm.vres-40)/2+20, wid% = mm.hres/6 Dim ang! = 0.087266463, rad90! = 1.570796327 '90 degrees in radians Dim string a$,b$,c$,d$,e$,http$,minute$,second$,item$,Values(10) length 20 Dim string names$(10) length 15 names(0)="description":names(1)="temp":names(2)="pressure":names(3)="humidity" names(4)="speed":names(5)="deg":names(6)="gust":names(7)="country":names(8)="name" names(9)="icon" Dim string labels$(10) length 25 labels$(0)="Sky": labels$(1)="Temperature": labels$(2)="Atmospheric Pressure" labels$(3)="Humidity": labels$(4)="Wind Speed": labels$(5)="From the" labels$(6)="Gusting to": labels$(7)="City": labels$(8)="," Dim string points$(16) length 3 =("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","","") points(15)="NNW": points(16)="N" dim string iconCodes$="01d02d03d04d09d10d11d13d50d" dim integer pESP_RST=98: pin(pESP_RST)=0: setpin pESP_RST,DOUT ' set up ESP-01 Reset pin low dim integer pInTemp=1,iFailedCnt,iEspStage,wOrgFailedFlag=1 Dim MYID$="6057856" ' Liverpool, Nova Scotia Dim APIKEY$="YourKeyGoesHere" Dim report$="weather", URL$="api.openweathermap.org" http$= "GET /data/2.5/"+report$+"?id="+MYID$+"&APPID="+APIKEY$ http$=http$+" HTTP/1.0"+Chr$(13)+Chr$(10)+Chr$(13)+Chr$(10) Dim string LOCALURL$="192.168.2.65" Dim string LOCALGET$= "GET /oat.html HTTP/1.0"+Chr$(13)+Chr$(10)+Chr$(13)+Chr$(10) if iconFlag then: geticons: endif open "com2:115200,8192" as #1 if mm.hres=320 then: txtFont=7: endif box 0,0,mm.hres,40,,rgb(white),grey box 0,40,mm.hres/2,mm.vres-40,2,rgb(white),lblue box mm.hres/2+1,40,mm.hres/2,mm.vres-40,2,rgb(white),lblue text mm.hres/2,5,"Weather: Milton, Nova Scotia",C,1,,rgb(white),grey text mm.hres/2,20,date$+" "+time$,C,1,,rgb(white),grey compass_rose cx%,cy%,wid% getWeather writeScreen getOAT a$=mid$(time$,4,2) ' get minutes i=val(a$) mod 15 if i < 5 then: firstPassFlag=0: endif ' GET won't violate 10 minute rule restart: do a$=mid$(time$,7,2) ' get second if second$<>a$ then text mm.hres/2,20,date$+" "+time$,C,1,,rgb(white),grey second$=a$ a$=mid$(time$,4,2) ' get minute if minute$<>a$ then minute$=a$ if wOrgFailedFlag or minute="00" or minute="15" or minute="30" or minute="45" then ' get weather if firstPassFlag then firstPassFlag=0 ' don't violate "no more than once every 10 minutes" rule else getWeather writeScreen endif endif getOAT endif endif i=tempr(pInTemp): if i<>1000 then: insideTemp=i: endif if oldInsideTemp<>insideTemp then oldInsideTemp=insideTemp text mm.hres/2+13,mm.vres*.80,"INSIDE",,txtFont,,rgb(black),lblue text mm.hres/2+10,mm.vres*.85,str$(insideTemp)+"C",,5,,rgb(gray),lblue logTmp endif if oldOutsideTemp<>outsideTemp then oldOutsideTemp=outsideTemp text mm.hres-65,mm.vres*.80,"OUTSIDE",,txtFont,,rgb(black),lblue text mm.hres-70,mm.vres*.85,str$(outsideTemp),,5,,rgb(gray),lblue endif loop sub writeScreen x=10:y=45: for i=0 to 6 if i=2 then text x,y,labels$(i)+": ",,txtFont,,rgb(black),lblue:y=y+15: text x,y," "+Values$(i),,txtFont,,rgb(black),lblue:y=y+15: else text x,y,labels$(i)+": "+Values$(i),,txtFont,,rgb(black),lblue):y=y+15: endif next i circle cx%,cy%,wid%-6,,,lblue,lblue circle cx%,cy%,wid%/8,,,rgb(red),rgb(red) ' center n=((630-degrees) mod 360) ' opposite of direction of wind text x,215,"Wind to "+str$(n),,txtFont,,rgb(black),lblue n=((degrees+180) mod 360) ' opposite of direction of wind for i=-3 to 3 ' lines offset from center (cx%) to make arrow x_endpoint=(cx%)+(Cos(n/5*ang!)*(wid%-8)) ' ang! = 0.087266463 (5 degrees) y_endpoint=(cy%)-(Sin(n/5*ang!)*(wid%-8)) Line (cx%+i),(cy%+i),x_endpoint,y_endpoint,,RGB(RED) Line (cx%-i),(cy%-i),x_endpoint,y_endpoint,,RGB(RED) ' Line (cx%+i),(cy%+i),(cx%)+(Cos(n*ang!)*(wid%-8)),(cy%)-(Sin(n*ang!)*(wid%-8)),,RGB(RED) next i ' text x,200,"Condition: ",,txtFont,,rgb(black),lblue text x,200,"Condition: "+Values(9),,txtFont,,rgb(black),lblue iconFlag=0 for i=0 to 8 ' check icon availability a$=mid$(iconCodes$,i*3+1,3) ' print a$+"="+Values(9)+"? "; if a$=Values$(9) then: iconFlag=i+1: exit for: endif next i if iconFlag then blit write iconFlag,mm.hres/4,180,50,50 else text x+10,212,Values$(0),,txtFont,,rgb(black),lblue endif end sub sub compass_rose cx%,cy%,wid% Local a% Text cx%-6,cy%-wid%-17),"N",L,1,,RGB(1,1,1),lblue Text cx%-6,cy%+wid%+5,"S",L,1,,RGB(1,1,1),lblue Text cx%+wid%+5,cy%-11,"E",L,1,,RGB(1,1,1),lblue Text cx%-(wid%)-10,cy%-11,"W",L,1,,RGB(1,1,1),lblue if a%<>a% then Text 10,10,"NE",L,7,,RGB(1,1,1),RGB(134,174,230) Image rotate 6,4,30,30,cx%+(wid%-16)*Cos(.785),cy%-(wid%-16)*Cos(.785),45,1 Text 10,10,"SE",L,7,,RGB(1,1,1),RGB(134,174,230) Image rotate 6,4,30,30,cx%+(wid%-16)*Cos(.785),cy%+(wid%-16)*Cos(.785),135,1 Text 10,10,"SW",L,7,,RGB(1,1,1),RGB(134,174,230) Image rotate 6,4,30,30,cx%-(wid%-16)*Cos(.785),cy%+(wid%-16)*Cos(.785),225,1 Text 10,10,"NW",L,7,,RGB(1,1,1),RGB(134,174,230) Image rotate 6,4,29,29,cx%-(wid%-16)*Cos(.785),cy%-(wid%-16)*Cos(.785),315,1 Text 10,10," ",L,7,,RGB(134,174,230),RGB(134,174,230) ' clear text ' tick marks, every 5 degrees (360/5 = 72) endif For a% = 0 To 71 ' note: for angles, East is zero Line (cx%)+(Cos(a%*ang!)*(wid%-4)),(cy%)-(Sin(a%*ang!)*(wid%-4)),(cx%)+(Cos(a%*ang!)*(wid%+1)),(cy%)-(Sin(a%*ang!)*(wid%+1)),,RGB(WHITE) Next ' COMPASS perimiter Circle cx%,cy%,wid% Circle cx%,cy%,wid%-4 circle cx%,cy%,wid%/8,,,rgb(red),rgb(red) ' center End Sub Sub getWeather if EspFlag then: getWeatherOrg ' print "Skipping getWeatherOrg" else Open "livr.jsn" For input As #2 Do While Not Eof(2) Line Input #2, a$: ' Print a$ LongString append ls%(),a$ Loop Close #2 ' LongString print ls%(): Print endif For n=0 To nNames-1 item$=names$(n) Values$(n)=pseudo_json$(ls%(),item$) ' Print item$,Values$(n) If item$="temp" Then: Values$(n)=Str$(Val(Values$(n))-273.15,0,1)+"C": EndIf If item$="deg" Then degrees=Val(Values$(n)) ' i=(degrees+11.25)/22.5 i=((450-degrees+11.25) mod 360)/22.5 Values$(n)=points$(i) ' print item$,degrees,i,Values$(n) EndIf If item$="humidity" Then: Values$(n)=Values$(n)+"%": EndIf If item$="speed" Then: Values$(n)=Values$(n)+"kph": EndIf If item$="pressure" Then: Values$(n)=Values$(n)+" millibars": EndIf If item$="gust" Then: Values$(n)=Values$(n)+"kph": EndIf Next n End Sub Function pseudo_json$(ls%(),key$) local integer i,j,k,l,m local string a,b m=1 pseudo_json$="" Do i=LInStr(ls%(),key$,m) ' Print key$,i If i Then a=LGetStr$(ls%(),i-1,1) b=LGetStr$(ls%(),i+Len(key$),1) ' Print "|";a;"|","|";b;"|"; If a=Chr$(34) And b=Chr$(34) Then ' found the key j=LInStr(ls%(),",",i+Len(key$)+2) If j>0 Then k=i+Len(key$)+2 a=LGetStr$(ls%(),k,j-k) ' Print a If Mid$(a,1,1)=Chr$(34) Then ' remove "s a=Mid$(a,2,Len(a)-2) EndIf If Instr(a,"}") Then: a=Mid$(a,1,Len(a)-1): EndIf ' strip "}" If mid$(a,len(a),1) = chr$(34) Then: a=Mid$(a,1,Len(a)-1): EndIf ' strip double-quote pseudo_json$=a Exit Do EndIf EndIf m=i+Len(key$) Else Exit Do ' key not found EndIf Loop End Function sub geticons local integer i,j,k,x,y Load image "icons.bmp" 'for i=1 to 9: on error skip: blit close i: next i k=1:x=0 for i=1 to 3 y=0 for j=1 to 3 blit read k,x,y,50,50: y=y+50:k=k+1 next j x=x+50: y=0 next i end sub Sub getWeatherOrg LongString clear ls%() wOrgFailedFlag=1 ESPInit if MYID$<>MYID$ then ' skip old initialization pause 8000 print #1,"AT+CIPSNTPCFG=1,-4,"+chr$(34)+"us.pool.ntp.org"+chr$(34)+chr$(13)+chr$(10); if NOT OKwait(5000) then errorexit("AT+CIPSNTPCFG") print #1,"AT+CIPSNTPTIME?"+chr$(13)+chr$(10); print "Time: ": pause 2000 do while loc(1)>0: print input$(1,1);: loop: print print "RTC Date/Time: "+date$+" "+time$ print #1,"AT+CWMODE_CUR=1"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("AT+CWMODE_CUR=1") print #1,"AT+CWJAP_CUR="+chr$(34)+"Omnibus_N"+chr$(34)+","+chr$(34)+"amber1977"+chr$(34)+chr$(13)+chr$(10); if NOT OKwait(10000) then errorexit("AT+CWJAP_CUR=") endif iEspStage=iEspStage+1 print #1,"AT+CIPSTART="+chr$(34)+"TCP"+chr$(34)+","+chr$(34)+URL$+chr$(34)+",80"+chr$(13)+chr$(10); if NOT OKwait(10000) then errorexit("AT+CIPSTART=") iEspStage=iEspStage+1 print #1,"AT+CIPMODE=1"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("AT+CIPMODE=1") 'do: loop iEspStage=iEspStage+1 print "Trying: "+http$ print #1,"AT+CIPSEND"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("AT+CIPSEND") print #1,http$; getinput(10000) print "Returned: "; longstring print ls%() ' lb a$=lgetstr$(ls%(),1,1) if a$="{" then wOrgFailedFlag=0 on error skip 4 open "weather.log" for append as #3 print #3, mid$(date$,9,2)+mid$(date$,4,2)+mid$(date$,1,2)+mid$(time$,1,2)+mid$(time$,4,2)+mid$(time$,7,2) longstring print #3, %ls() close #3 endif print #1,"+++"; pause 1000 iEspStage=iEspStage+1 print #1,"AT+CIPMODE=0"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("AT+CIPMODE=0") iEspStage=iEspStage+1 print #1,"AT+CIPCLOSE"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("AT+CIPCLOSE") 'do:loop end sub function OKwait(timeout as integer) as integer OKwait=1 timer=0 do loop until input$(1,1)="O" or timer>=timeout do loop until input$(1,1)="K" or timer>=timeout if timer>=timeout then OKwait=0 end function sub errorexit(calling as string) print "AT call timeout from - ",calling print #1,"AT+CIPCLOSE"+chr$(13)+chr$(10) iFailedCnt=iFailedCnt+1 if iFailedCnt > 5 then: end: : endif 'goto restart end sub sub getinput(waitpause as integer) local a$ local j%,i%=-1 timer=0 do a$=input$(1,1) If a$<>"" Then LongString append ls%(),a$ ' print a$; if a$="{" then if i%=-1 then i%=1 else i%=i%+1 endif endif if a$="}" then i%=i%-1 endif loop while timer<=waitpause and i%<>0 j%=LInStr(ls%(),"{") ' print "TCP: ";j%;" ";: longstring print ls%() if j%>0 then: LongString trim ls%(),j%-1: endif 'print "" end sub sub ESPInit iEspStage=1 ESPOKFlag%=0 for i=1 to 5 print "AT+"; print #1,"AT"+chr$(13)+chr$(10); if OKwait(5000) then: ESPOKFlag%=1: exit for: endif pin(pESP_RST)=0: pause 1000: pin(pESP_RST)=1: pause 2000 ' toggle reset pin next i if not ESPOKFlag% then for i=1 to 5 print "RST "; print #1,"RST"+chr$(13)+chr$(10); pause 5000 print #1,"AT"+chr$(13)+chr$(10); if OKwait(5000) then: ESPOKFlag%=1: exit for: endif next i endif end sub sub getOAT ' Outside Air Temperature (html get) longstring clear ls%() print "OAT: ESPinit: "; ESPInit iEspStage=iEspStage+1 a$="AT+CIPSTART="+chr$(34)+"TCP"+chr$(34)+","+chr$(34)+LOCALURL$+chr$(34)+",80" print a$ print #1,a$+chr$(13)+chr$(10); if NOT OKwait(10000) then errorexit("OAT: AT+CIPSTART=") iEspStage=iEspStage+1 print #1,"AT+CIPMODE=1"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("OAT: AT+CIPMODE=1") print "Trying: "+mid$(LOCALGET$,1,len(LOCALGET$)-4)+": "; iEspStage=iEspStage+1 print #1,"AT+CIPSEND"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("OAT: AT+CIPSEND") print #1,LOCALGET$; getinput(10000) ' print "Local Return: "; ' longstring print ls%() ' lb a$=lgetstr$(ls%(),2,10) ' more characters than valid i=val(a$) if i>-40 and i < 50 then print i if i<>outsideTemp then outsideTemp=i logTmp endif else endif print #1,"+++"; pause 1000 iEspStage=iEspStage+1 print #1,"AT+CIPMODE=0"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("OAT: AT+CIPMODE=0") iEspStage=iEspStage+1 print #1,"AT+CIPCLOSE"+chr$(13)+chr$(10); if NOT OKwait(4000) then errorexit("OAT: AT+CIPCLOSE") end sub sub logTmp on error skip 4 open "wtemp.log" for append as #3 a$=mid$(date$,9,2)+mid$(date$,4,2)+mid$(date$,1,2)+mid$(time$,1,2)+mid$(time$,4,2)+mid$(time$,7,2) print #3,"T "+str$(insideTemp)+" "+str$(outsideTemp)+" ~ "+a$ close #3 i=0 ' null end sub Edited 2021-02-19 08:27 by lizby PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Chopperp![]() Guru ![]() Joined: 03/01/2018 Location: AustraliaPosts: 1090 |
All I can say is "Wow" I find SAVE IMAGE File$ works well. ChopperP |
||||
lizby Guru ![]() Joined: 17/05/2016 Location: United StatesPosts: 3314 |
Perfect, thank you. ![]() Edited 2021-02-19 08:57 by lizby PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |